mirror of
https://github.com/zulip/zulip.git
synced 2025-11-08 16:01:58 +00:00
schedulemessages: Add delivery system for scheduled message.
This commit is contained in:
@@ -85,6 +85,20 @@ stdout_logfile_maxbytes=20MB ; max # logfile bytes b4 rotation (default 50MB)
|
|||||||
stdout_logfile_backups=3 ; # of stdout logfile backups (default 10)
|
stdout_logfile_backups=3 ; # of stdout logfile backups (default 10)
|
||||||
directory=/home/zulip/deployments/current/
|
directory=/home/zulip/deployments/current/
|
||||||
|
|
||||||
|
[program:zulip_deliver_scheduled_messages]
|
||||||
|
command=/home/zulip/deployments/current/manage.py deliver_scheduled_messages
|
||||||
|
priority=350 ; the relative start priority (default 999)
|
||||||
|
autostart=true ; start at supervisord start (default: true)
|
||||||
|
autorestart=true ; whether/when to restart (default: unexpected)
|
||||||
|
stopsignal=TERM ; signal used to kill process (default TERM)
|
||||||
|
topwaitsecs=30 ; max num secs to wait b4 SIGKILL (default 10)
|
||||||
|
user=zulip ; setuid to this UNIX account to run the program
|
||||||
|
redirect_stderr=true ; redirect proc stderr to stdout (default false)
|
||||||
|
stdout_logfile=/var/log/zulip/scheduled_message_deliverer.log ; stdout log path, NONE for none; default AUTO
|
||||||
|
stdout_logfile_maxbytes=20MB ; max # logfile bytes b4 rotation (default 50MB)
|
||||||
|
stdout_logfile_backups=3 ; # of stdout logfile backups (default 10)
|
||||||
|
directory=/home/zulip/deployments/current/
|
||||||
|
|
||||||
[program:zulip_events_message_sender]
|
[program:zulip_events_message_sender]
|
||||||
command=/home/zulip/deployments/current/manage.py process_queue --queue_name=message_sender --worker_num=%(process_num)s
|
command=/home/zulip/deployments/current/manage.py process_queue --queue_name=message_sender --worker_num=%(process_num)s
|
||||||
process_name=%(program_name)s-%(process_num)s
|
process_name=%(program_name)s-%(process_num)s
|
||||||
@@ -108,9 +122,9 @@ numprocs=<%= @message_sender_processes %>
|
|||||||
[group:zulip-workers]
|
[group:zulip-workers]
|
||||||
<% if @queues_multiprocess %>
|
<% if @queues_multiprocess %>
|
||||||
; each refers to 'x' in [program:x] definitions
|
; each refers to 'x' in [program:x] definitions
|
||||||
programs=zulip_deliver_enqueued_emails, <% @queues.each_with_index do |queue, i| -%>zulip_events_<%= queue %><%= ',' if i < (@queues.size - 1) %> <% end -%>
|
programs=zulip_deliver_enqueued_emails, zulip_deliver_scheduled_messages, <% @queues.each_with_index do |queue, i| -%>zulip_events_<%= queue %><%= ',' if i < (@queues.size - 1) %> <% end -%>
|
||||||
<% else %>
|
<% else %>
|
||||||
programs=zulip_deliver_enqueued_emails, zulip_events
|
programs=zulip_deliver_enqueued_emails, zulip_events, zulip_deliver_scheduled_messages
|
||||||
<% end %>
|
<% end %>
|
||||||
|
|
||||||
[group:zulip-senders]
|
[group:zulip-senders]
|
||||||
|
|||||||
@@ -151,7 +151,8 @@ cmds = [['./tools/compile-handlebars-templates', 'forever'],
|
|||||||
manage_args + ['127.0.0.1:%d' % (tornado_port,)],
|
manage_args + ['127.0.0.1:%d' % (tornado_port,)],
|
||||||
['./tools/run-dev-queue-processors'] + manage_args,
|
['./tools/run-dev-queue-processors'] + manage_args,
|
||||||
['env', 'PGHOST=127.0.0.1', # Force password authentication using .pgpass
|
['env', 'PGHOST=127.0.0.1', # Force password authentication using .pgpass
|
||||||
'./puppet/zulip/files/postgresql/process_fts_updates']]
|
'./puppet/zulip/files/postgresql/process_fts_updates'],
|
||||||
|
['./manage.py', 'deliver_scheduled_messages']]
|
||||||
if options.test:
|
if options.test:
|
||||||
# Webpack doesn't support 2 copies running on the same system, so
|
# Webpack doesn't support 2 copies running on the same system, so
|
||||||
# in order to support running the Casper tests while a Zulip
|
# in order to support running the Casper tests while a Zulip
|
||||||
|
|||||||
56
zerver/management/commands/deliver_scheduled_messages.py
Normal file
56
zerver/management/commands/deliver_scheduled_messages.py
Normal file
@@ -0,0 +1,56 @@
|
|||||||
|
import logging
|
||||||
|
import time
|
||||||
|
from typing import Any, Dict
|
||||||
|
from datetime import timedelta
|
||||||
|
|
||||||
|
from django.conf import settings
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from django.db import transaction
|
||||||
|
from django.utils.timezone import now as timezone_now
|
||||||
|
|
||||||
|
from zerver.lib.context_managers import lockfile
|
||||||
|
from zerver.lib.logging_util import log_to_file
|
||||||
|
from zerver.models import ScheduledMessage, Message
|
||||||
|
from zerver.lib.actions import do_send_messages
|
||||||
|
from zerver.lib.addressee import Addressee
|
||||||
|
|
||||||
|
## Setup ##
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
log_to_file(logger, settings.SCHEDULED_MESSAGE_DELIVERER_LOG_PATH)
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = """Deliver scheduled messages from the ScheduledMessage table.
|
||||||
|
Run this command under supervisor.
|
||||||
|
|
||||||
|
Usage: ./manage.py deliver_scheduled_messages
|
||||||
|
"""
|
||||||
|
|
||||||
|
def construct_message(self, scheduled_message: ScheduledMessage) -> Dict[str, Any]:
|
||||||
|
message = Message()
|
||||||
|
message.sender = scheduled_message.sender
|
||||||
|
message.content = scheduled_message.content
|
||||||
|
message.recipient = scheduled_message.recipient
|
||||||
|
message.subject = scheduled_message.subject
|
||||||
|
message.pub_date = timezone_now()
|
||||||
|
message.sending_client = scheduled_message.sending_client
|
||||||
|
|
||||||
|
return {'message': message, 'stream': scheduled_message.stream,
|
||||||
|
'realm': scheduled_message.realm}
|
||||||
|
|
||||||
|
def handle(self, *args: Any, **options: Any) -> None:
|
||||||
|
with lockfile("/tmp/zulip_scheduled_message_deliverer.lockfile"):
|
||||||
|
while True:
|
||||||
|
messages_to_deliver = ScheduledMessage.objects.filter(
|
||||||
|
scheduled_timestamp__lte=timezone_now(),
|
||||||
|
delivered=False)
|
||||||
|
if messages_to_deliver:
|
||||||
|
for message in messages_to_deliver:
|
||||||
|
with transaction.atomic():
|
||||||
|
do_send_messages([self.construct_message(message)])
|
||||||
|
message.delivered = True
|
||||||
|
message.save(update_fields=['delivered'])
|
||||||
|
|
||||||
|
cur_time = timezone_now()
|
||||||
|
time_next_min = (cur_time + timedelta(minutes=1)).replace(second=0, microsecond=0)
|
||||||
|
sleep_time = (time_next_min - cur_time).total_seconds()
|
||||||
|
time.sleep(sleep_time)
|
||||||
@@ -1203,6 +1203,8 @@ ZULIP_PATHS = [
|
|||||||
("API_KEY_ONLY_WEBHOOK_LOG_PATH", "/var/log/zulip/webhooks_errors.log"),
|
("API_KEY_ONLY_WEBHOOK_LOG_PATH", "/var/log/zulip/webhooks_errors.log"),
|
||||||
("SOFT_DEACTIVATION_LOG_PATH", "/var/log/zulip/soft_deactivation.log"),
|
("SOFT_DEACTIVATION_LOG_PATH", "/var/log/zulip/soft_deactivation.log"),
|
||||||
("TRACEMALLOC_DUMP_DIR", "/var/log/zulip/tracemalloc"),
|
("TRACEMALLOC_DUMP_DIR", "/var/log/zulip/tracemalloc"),
|
||||||
|
("SCHEDULED_MESSAGE_DELIVERER_LOG_PATH",
|
||||||
|
"/var/log/zulip/scheduled_message_deliverer.log"),
|
||||||
]
|
]
|
||||||
|
|
||||||
# The Event log basically logs most significant database changes,
|
# The Event log basically logs most significant database changes,
|
||||||
@@ -1399,6 +1401,9 @@ LOGGING = {
|
|||||||
'zerver.management.commands.enqueue_digest_emails': {
|
'zerver.management.commands.enqueue_digest_emails': {
|
||||||
'level': 'DEBUG',
|
'level': 'DEBUG',
|
||||||
},
|
},
|
||||||
|
'zerver.management.commands.deliver_scheduled_messages': {
|
||||||
|
'level': 'DEBUG',
|
||||||
|
},
|
||||||
'zulip.management': {
|
'zulip.management': {
|
||||||
'handlers': ['file', 'errors_file'],
|
'handlers': ['file', 'errors_file'],
|
||||||
'propagate': False,
|
'propagate': False,
|
||||||
|
|||||||
Reference in New Issue
Block a user