Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

uWSGI Signal framework: signal to ALL workers being sent to the first available workers

I am deploying a Flask app using uWSGI running in a docker container. In the app, which has 4 workers, there are some in-memory dictionaries that store "cached values" used by the application to prevent the need to query the DB everytime. These dicts are created when the workers are initialized and I am trying to use uWSGI's Signal Framework to force an update of the caches in all workers.

My initial idea was:

  1. Define a function that updates the dictionaries in all workers.
  2. Register this function as a handler for a signal that targets all workers (target="workers").
  3. Trigger the signal when needed.

Example:

def update_dicts(sig):
    # Update dictionaries here
    print('Received signal {}: updating dicts in worker {}'.format(sig, uwsgi.worker_id()))

uwsgi.register_signal(100, "workers", update_dicts)

and trigger the signal in any worker when needed:

uwsgi.signal(100)

However, even with the signal targeting "workers", the signal is received and handled by only one worker, as if it had "worker" as target.

I also tried registering one signal for each worker (using target "workerN") and triggering all of them, but the signals are being sent to any worker, and not to the specified worker:

# Each worker executes this 
# Signal registrations: 111, 112, 113, 114
uwsgi.register_signal(110 + uwsgi.worker_id(), "worker{}".format(uwsgi.worker_id()), update_service_dicts)

# To trigger the signals:
for i in [1,2,3,4]:
    uwsgi.signal(110 + i)

Application's log:

[uwsgi-signal] signum 113 registered (wid: 3 modifier1: 0 target: worker3)
[uwsgi-signal] signum 112 registered (wid: 2 modifier1: 0 target: worker2)
[uwsgi-signal] signum 114 registered (wid: 4 modifier1: 0 target: worker4)
[uwsgi-signal] signum 111 registered (wid: 1 modifier1: 0 target: worker1)
Mon Jun  5 18:17:51 2017 - error managing signal 112 on worker 4
Received signal 111: updating dicts in worker 1.
Received signal 113: updating dicts in worker 3.
Received signal 114: updating dicts in worker 4.

Triggering another time:

Mon Jun  5 18:18:01 2017 - error managing signal 111 on worker 4
Mon Jun  5 18:18:01 2017 - error managing signal 113 on worker 4
Mon Jun  5 18:18:01 2017 - error managing signal 112 on worker 4
Received signal 114: updating dicts in worker 4.

Am I missing something here or are these targets not yet implemented?

I am currently using the following uwsgi configurations:

[uwsgi]

die-on-term = true

http = 0.0.0.0:9090
mount = /=/path/to/my/app/file.py
callable = app
chdir = /path/to/my/app/

; enable the stats server on port 9191
stats = 0.0.0.0:9191

; log configuration
logto = /var/log/uwsgi/uwsgi.log

; spawn 2 threads in 4 processes (concurrency level: 8)
processes = 4
threads = 2

; drop privileges
uid = pmais
gid = pmais

; Loads apps independently to solve error related to DB connection:
;     "SSL error: decryption failed or bad record mac uwsgi"
; Reference: http://stackoverflow.com/a/22753269
lazy-apps = true

catch-exceptions = true
like image 982
fabiocapsouza Avatar asked Nov 18 '22 18:11

fabiocapsouza


1 Answers

I had similar problems and changed the signalling to 'active-workers' instead of 'workers', as the signalling queue may overflow if non-active workers are signalled. See also https://github.com/unbit/uwsgi/issues/775

def update_dicts(sig):
    # Update dictionaries here
    print('Received signal {}: updating dicts in worker {}'.format(sig, uwsgi.worker_id()))
    
    uwsgi.register_signal(100, "active-workers", update_dicts)

Also be aware that using 'lazy-apps' will load the app in the workers, possibly registering the signal multiple times.

like image 125
TvR Avatar answered Jan 18 '23 23:01

TvR