erondem
erondem

Reputation: 582

How to make requests while program in infinite loop with multiprocessing

I have two function which are require to run same time. read_card needs to run in an infinite loop and waits for new cards(it is actually a Nrf reader) and adds some string to a queue , send_data suppose to get values from queue and send them to the server via requests library.Everything works when I do not use multiprocessing. But I need concurrency I guess.

Here is my two function.

def read_card(reader, configs):
    print("First started")
    while True:
        authorized_uid = reader.is_granted(reader.read())
        print("Waiting for card")
        #TODO:If not authorized in AccessList.txt look to the server
        if authorized_uid is not None:
            print(authorized_uid)
            open_door()
            check_model = CheckModel(configs.DeviceSerialNumber, authorized_uid)
            message_helper.put_message(check_model)

def send_data(sender):
    print("Second started")
    while True:
        message_model = message_helper.get_message()
        if message_model is not None:
            sender.send_message(message_model)

Here is how I call main

def main():
    download_settings()
    create_folders()
    settings = read_settings()
    accessList = get_user_list(settings)
    configure_scheduler(settings)  

    message_sender = MessageSender(client.check,client.bulk)

    reader_process = multiprocessing.Process(name = "reader_loop", target = read_card, args=(Reader(accessList, entryLogger),configs,))
    message_process = multiprocessing.Process(name = "message_loop", target = send_data, args=(message_sender,))
    reader_process.start()
    message_process.start()

if __name__ == '__main__':
    main()

And those are for debugging. I printed what put_message and send_message from different classes.

def send_message(self,model):
    print(model)
    return self.checkClient.check(model)

def put_message(self, message):
    print(message)
    self.put_to_queue(self.queue, message)
    self.put_to_db(message)

I expect to see some object names in terminal, but I only see below. Also reader does not work.

First started
Second started

Which part I do wrong?

Upvotes: 0

Views: 502

Answers (1)

abdusco
abdusco

Reputation: 11091

Use a Queue to communicate between processes. Then when you read a card inside reader create a new job and push it into the queue, then pop this job inside the processor and send the request.

Here's a proof of concept:

from datetime import datetime
from multiprocessing import Process, Queue
from random import random
from time import sleep

import requests


def reader(q: Queue):
    while True:
        # create a job
        job = {'date': datetime.now().isoformat(), 'number': random()}
        q.put(job)
        # use a proper logger instead of printing,
        # otherwise you'll get mangled output!
        print('Enqueued new job', job)
        sleep(5)


def client(q: Queue):
    while True:
        # wait for a new job
        job = q.get()
        res = requests.post(url='https://httpbin.org/post',
                            data=job)
        res.raise_for_status()
        json = res.json()
        print(json['form'])


if __name__ == '__main__':
    q = Queue()
    reader_proc = Process(name='reader', target=reader, args=(q,))
    client_proc = Process(name='client', target=client, args=(q,))

    procs = [reader_proc, client_proc]
    for p in procs:
        print(f'{p.name} started')
        p.start()
    for p in procs:
        p.join()

which prints:

reader started
client started
Enqueued new job {'date': '2019-07-01T15:51:53.100395', 'number': 0.7659293922700549}
{'date': '2019-07-01T15:51:53.100395', 'number': '0.7659293922700549'}
Enqueued new job {'date': '2019-07-01T15:51:58.116020', 'number': 0.14306347124900576}
{'date': '2019-07-01T15:51:58.116020', 'number': '0.14306347124900576'}

Upvotes: 1

Related Questions