Sends a WebSocket group message. In gevent-patched uWSGI workers, asyncio event loop creation fails because monkey-patching removes select.epoll. For those contexts a synchronous Redis path is used instead, matching the channels_redis 4.x wire format. Celery prefork workers ma
(group_name, event_type, data, collect_garbage=False)
| 474 | |
| 475 | |
| 476 | def send_websocket_update(group_name, event_type, data, collect_garbage=False): |
| 477 | """ |
| 478 | Sends a WebSocket group message. |
| 479 | |
| 480 | In gevent-patched uWSGI workers, asyncio event loop creation fails because |
| 481 | monkey-patching removes select.epoll. For those contexts a synchronous Redis |
| 482 | path is used instead, matching the channels_redis 4.x wire format. |
| 483 | |
| 484 | Celery prefork workers may inherit gevent monkey-patching without a running |
| 485 | gevent hub; in that case gevent.spawn would never execute, so delivery is |
| 486 | synchronous via Redis instead. |
| 487 | """ |
| 488 | message = {'type': event_type, 'data': data} |
| 489 | |
| 490 | if _should_use_sync_websocket_send(): |
| 491 | _gevent_ws_send(group_name, message) |
| 492 | elif _is_gevent_monkey_patched(): |
| 493 | import gevent |
| 494 | gevent.spawn(_gevent_ws_send, group_name, message) |
| 495 | else: |
| 496 | # Not gevent-patched (plain Celery, tests) — use asyncio channel layer |
| 497 | try: |
| 498 | async_to_sync(get_channel_layer().group_send)(group_name, message) |
| 499 | except Exception as e: |
| 500 | logger.warning(f"Failed to send WebSocket update: {e}") |
| 501 | |
| 502 | if collect_garbage: |
| 503 | gc.collect() |
| 504 | |
| 505 | def send_websocket_event(event, success, data): |
| 506 | """Acquire a lock to prevent concurrent task execution.""" |