1
This commit is contained in:
parent
e86c528013
commit
b67c326aa3
@ -17,6 +17,7 @@ MAX_DELIVERY_ATTEMPTS=3
|
|||||||
RETRY_BACKOFF_SECONDS=60
|
RETRY_BACKOFF_SECONDS=60
|
||||||
FEISHU_TIMEOUT_SECONDS=10
|
FEISHU_TIMEOUT_SECONDS=10
|
||||||
DISPATCH_INLINE=false
|
DISPATCH_INLINE=false
|
||||||
|
DISPATCH_WAKEUP_ON_RECEIVE=true
|
||||||
DELIVERY_BATCH_SIZE=100
|
DELIVERY_BATCH_SIZE=100
|
||||||
DELIVERY_CONCURRENCY=5
|
DELIVERY_CONCURRENCY=5
|
||||||
WORKER_INTERVAL_SECONDS=15
|
WORKER_INTERVAL_SECONDS=2
|
||||||
|
|||||||
@ -20,9 +20,10 @@ class Settings:
|
|||||||
feishu_timeout_seconds: int = 10
|
feishu_timeout_seconds: int = 10
|
||||||
timezone: str = ""
|
timezone: str = ""
|
||||||
dispatch_inline: bool = False
|
dispatch_inline: bool = False
|
||||||
|
dispatch_wakeup_on_receive: bool = True
|
||||||
delivery_batch_size: int = 100
|
delivery_batch_size: int = 100
|
||||||
delivery_concurrency: int = 5
|
delivery_concurrency: int = 5
|
||||||
worker_interval_seconds: int = 15
|
worker_interval_seconds: int = 2
|
||||||
|
|
||||||
|
|
||||||
def get_settings() -> Settings:
|
def get_settings() -> Settings:
|
||||||
@ -40,7 +41,9 @@ def get_settings() -> Settings:
|
|||||||
feishu_timeout_seconds=int(os.getenv("FEISHU_TIMEOUT_SECONDS", "10")),
|
feishu_timeout_seconds=int(os.getenv("FEISHU_TIMEOUT_SECONDS", "10")),
|
||||||
timezone=os.getenv("APP_TIMEZONE") or os.getenv("TZ", ""),
|
timezone=os.getenv("APP_TIMEZONE") or os.getenv("TZ", ""),
|
||||||
dispatch_inline=os.getenv("DISPATCH_INLINE", "").lower() in {"1", "true", "yes", "on"},
|
dispatch_inline=os.getenv("DISPATCH_INLINE", "").lower() in {"1", "true", "yes", "on"},
|
||||||
|
dispatch_wakeup_on_receive=os.getenv("DISPATCH_WAKEUP_ON_RECEIVE", "true").lower()
|
||||||
|
in {"1", "true", "yes", "on"},
|
||||||
delivery_batch_size=int(os.getenv("DELIVERY_BATCH_SIZE", "100")),
|
delivery_batch_size=int(os.getenv("DELIVERY_BATCH_SIZE", "100")),
|
||||||
delivery_concurrency=int(os.getenv("DELIVERY_CONCURRENCY", "5")),
|
delivery_concurrency=int(os.getenv("DELIVERY_CONCURRENCY", "5")),
|
||||||
worker_interval_seconds=int(os.getenv("WORKER_INTERVAL_SECONDS", "15")),
|
worker_interval_seconds=int(os.getenv("WORKER_INTERVAL_SECONDS", "2")),
|
||||||
)
|
)
|
||||||
|
|||||||
@ -4,6 +4,7 @@ import html
|
|||||||
import json
|
import json
|
||||||
import mimetypes
|
import mimetypes
|
||||||
import os
|
import os
|
||||||
|
import threading
|
||||||
import urllib.error
|
import urllib.error
|
||||||
import urllib.request
|
import urllib.request
|
||||||
from datetime import datetime, timezone
|
from datetime import datetime, timezone
|
||||||
@ -29,6 +30,31 @@ class AppContext:
|
|||||||
self.db = Database(settings)
|
self.db = Database(settings)
|
||||||
self.db.migrate(settings)
|
self.db.migrate(settings)
|
||||||
self.dispatcher = Dispatcher(self.db, settings)
|
self.dispatcher = Dispatcher(self.db, settings)
|
||||||
|
self.dispatch_wakeup_lock = threading.Lock()
|
||||||
|
self.dispatch_wakeup_running = False
|
||||||
|
|
||||||
|
def wake_dispatcher(self) -> None:
|
||||||
|
if self.settings.dispatch_inline or not self.settings.dispatch_wakeup_on_receive:
|
||||||
|
return
|
||||||
|
with self.dispatch_wakeup_lock:
|
||||||
|
if self.dispatch_wakeup_running:
|
||||||
|
return
|
||||||
|
self.dispatch_wakeup_running = True
|
||||||
|
thread = threading.Thread(target=self._run_dispatch_wakeup, name="dispatch-wakeup", daemon=True)
|
||||||
|
thread.start()
|
||||||
|
|
||||||
|
def _run_dispatch_wakeup(self) -> None:
|
||||||
|
try:
|
||||||
|
while True:
|
||||||
|
processed = self.dispatcher.process_due_deliveries(
|
||||||
|
limit=self.settings.delivery_batch_size,
|
||||||
|
concurrency=self.settings.delivery_concurrency,
|
||||||
|
)
|
||||||
|
if processed < self.settings.delivery_batch_size:
|
||||||
|
break
|
||||||
|
finally:
|
||||||
|
with self.dispatch_wakeup_lock:
|
||||||
|
self.dispatch_wakeup_running = False
|
||||||
|
|
||||||
|
|
||||||
def json_response(handler: BaseHTTPRequestHandler, status: int, payload: dict[str, Any] | list[Any]) -> None:
|
def json_response(handler: BaseHTTPRequestHandler, status: int, payload: dict[str, Any] | list[Any]) -> None:
|
||||||
@ -488,6 +514,7 @@ class Handler(BaseHTTPRequestHandler):
|
|||||||
"interval_seconds": self.context.settings.worker_interval_seconds,
|
"interval_seconds": self.context.settings.worker_interval_seconds,
|
||||||
},
|
},
|
||||||
"dispatch_inline": self.context.settings.dispatch_inline,
|
"dispatch_inline": self.context.settings.dispatch_inline,
|
||||||
|
"dispatch_wakeup_on_receive": self.context.settings.dispatch_wakeup_on_receive,
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -501,6 +528,8 @@ class Handler(BaseHTTPRequestHandler):
|
|||||||
try:
|
try:
|
||||||
payload = parse_json_body(self)
|
payload = parse_json_body(self)
|
||||||
result = self.context.dispatcher.receive_alert(payload)
|
result = self.context.dispatcher.receive_alert(payload)
|
||||||
|
if result.get("delivery_ids"):
|
||||||
|
self.context.wake_dispatcher()
|
||||||
json_response(self, 202, result)
|
json_response(self, 202, result)
|
||||||
except ValidationError as exc:
|
except ValidationError as exc:
|
||||||
json_response(self, 400, {"error": str(exc)})
|
json_response(self, 400, {"error": str(exc)})
|
||||||
|
|||||||
@ -14,6 +14,7 @@ services:
|
|||||||
RETRY_BACKOFF_SECONDS: ${RETRY_BACKOFF_SECONDS:-60}
|
RETRY_BACKOFF_SECONDS: ${RETRY_BACKOFF_SECONDS:-60}
|
||||||
FEISHU_TIMEOUT_SECONDS: ${FEISHU_TIMEOUT_SECONDS:-10}
|
FEISHU_TIMEOUT_SECONDS: ${FEISHU_TIMEOUT_SECONDS:-10}
|
||||||
DISPATCH_INLINE: ${DISPATCH_INLINE:-false}
|
DISPATCH_INLINE: ${DISPATCH_INLINE:-false}
|
||||||
|
DISPATCH_WAKEUP_ON_RECEIVE: ${DISPATCH_WAKEUP_ON_RECEIVE:-true}
|
||||||
DELIVERY_BATCH_SIZE: ${DELIVERY_BATCH_SIZE:-100}
|
DELIVERY_BATCH_SIZE: ${DELIVERY_BATCH_SIZE:-100}
|
||||||
DELIVERY_CONCURRENCY: ${DELIVERY_CONCURRENCY:-5}
|
DELIVERY_CONCURRENCY: ${DELIVERY_CONCURRENCY:-5}
|
||||||
volumes:
|
volumes:
|
||||||
@ -33,9 +34,10 @@ services:
|
|||||||
RETRY_BACKOFF_SECONDS: ${RETRY_BACKOFF_SECONDS:-60}
|
RETRY_BACKOFF_SECONDS: ${RETRY_BACKOFF_SECONDS:-60}
|
||||||
FEISHU_TIMEOUT_SECONDS: ${FEISHU_TIMEOUT_SECONDS:-10}
|
FEISHU_TIMEOUT_SECONDS: ${FEISHU_TIMEOUT_SECONDS:-10}
|
||||||
DISPATCH_INLINE: ${DISPATCH_INLINE:-false}
|
DISPATCH_INLINE: ${DISPATCH_INLINE:-false}
|
||||||
|
DISPATCH_WAKEUP_ON_RECEIVE: ${DISPATCH_WAKEUP_ON_RECEIVE:-true}
|
||||||
DELIVERY_BATCH_SIZE: ${DELIVERY_BATCH_SIZE:-100}
|
DELIVERY_BATCH_SIZE: ${DELIVERY_BATCH_SIZE:-100}
|
||||||
DELIVERY_CONCURRENCY: ${DELIVERY_CONCURRENCY:-5}
|
DELIVERY_CONCURRENCY: ${DELIVERY_CONCURRENCY:-5}
|
||||||
WORKER_INTERVAL_SECONDS: ${WORKER_INTERVAL_SECONDS:-15}
|
WORKER_INTERVAL_SECONDS: ${WORKER_INTERVAL_SECONDS:-2}
|
||||||
volumes:
|
volumes:
|
||||||
- dispatcher-data:/data
|
- dispatcher-data:/data
|
||||||
|
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user