0

I've been trying to share a multiprocessing manager dict with a web server so far with little success. The dict contains information but somehow it is not propagated to the running web server. The goal ultimately is to be able to intermittently poll data from the shared dictionary while the processes are running.

The output from the main process is [('foo', 0), ('bar', '1')] But when I make a get request I get an empty dict and a key error respectively.

from multiprocessing import Process, Manager
from pprint import pprint

from sanic import Sanic, json

app = Sanic(name='status_app')

manager_dict = {}
process_dict = {}


@app.get('/status')
def status(request):
    return json(manager_dict)


@app.get('/status/<pair:str>/')
def status_ext(request, pair):
    return json({pair: manager_dict[pair]})


def run_async_server():
    app.run(host="0.0.0.0", port=8000)
    return True


def build_process_dict():
    global process_dict
    process_dict = {
        'server': Process(target=run_async_server)
    }
    for _, p in process_dict.items():
        p.start()

    for _, p in process_dict.items():
        p.join()


def build_manager_dict():
    global manager_dict
    manager_dict = Manager().dict()
    manager_dict['foo'] = 0
    manager_dict['bar'] = '1'


if __name__ == '__main__':
    build_manager_dict()
    pprint(manager_dict.items())
    build_process_dict()
  • "But when I make a get request I get an empty dict and a key error respectively." I can't reproduce this error. If I run this code locally, `curl localhost:8000/status/foo` returns `{"foo":0}`, and `curl localhost:8000/status/bar` returns `{"bar":"1"}`. – larsks May 08 '22 at 03:31
  • Ok, that's strange, could it be an os issue? I'm running windows 10 and developing with pycharm – Dr Acme Isme May 08 '22 at 03:46
  • I'm not sure! I was running your code on Linux, so maybe? – larsks May 08 '22 at 11:52
  • Well, needless to say you are on the superior os, but I'll say it anyway :) – Dr Acme Isme May 08 '22 at 16:28

1 Answers1

0

I actually found a way to inject the manager into the app's context. This solved the problem for me. I'd be interested to know why the above code worked for others.

from multiprocessing import Process, Manager
from pprint import pprint

from sanic import Sanic, json

app = Sanic(name='status_app')

@app.get('/status')
async def status(request):
    return json(dict(app.ctx.manager_dict))


@app.get('/status/<pair:str>/')
async def status_ext(request, pair):
    return json({pair: app.ctx.manager_dict[pair]})


def run_async_server(manager_dict):
    app.ctx.manager_dict = manager_dict
    app.run(host="0.0.0.0", port=8000)
    return True


def build_manager_dict():
    global manager_dict
    manager_dict = Manager().dict()
    manager_dict['foo'] = 0
    manager_dict['bar'] = '1'


def build_process_dict():
    global process_dict
    process_dict = {
        'server': Process(target=run_async_server, args=[manager_dict]),
    }
    for _, p in process_dict.items():
        p.start()

    for _, p in process_dict.items():
        p.join()


if __name__ == '__main__':
    build_manager_dict()
    pprint(manager_dict.items())
    build_process_dict()