SIENTIAPDE-2013: cap load_latest_data's Mongo fetch at a configurable batch size
A cold start or notification storm had no backstop: load_latest_data fetched the entire matching backlog in one query. Confirmed live during SIENTIAPDE-2012's cluster verification -- an empty Redis cursor plus a real recurring error let a single run's query exceed Temporal's 4MB message limit and get stuck retrying forever. Threads a new notification_queue_batch_size config (env var NOTIFICATION_QUEUE_BATCH_SIZE, default 5000) through to the repository's find(), hard cap per run, no drain loop -- the incremental last_data_timestamp cursor picks up any remainder next run, per the parent ticket's design decision. Sorts by timestamp ascending so a capped run always returns the oldest pending documents first; without that, a capped batch has no guarantee of hitting the oldest documents, and the cursor would advance past whatever it skipped. Requires sientia_do>=1.13.0 (adds limit/sort params to MongoDBRepository.find in both the sync and async client) -- bumped the pin here per the parent ticket's decision to do it in the same PR. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -84,6 +84,7 @@ class Activities(TemporalManager, SlotManager, Formatters, MongoDB, Email, Postg
|
||||
connection_string=mongodb_config['connection_string'],
|
||||
database_name=mongodb_config['database_name'],
|
||||
ttl_index_seconds=mongodb_config['ttl_index_seconds'],
|
||||
notification_queue_batch_size=mongodb_config['notification_queue_batch_size'],
|
||||
logger=logger,
|
||||
notification_handler=notification_handler,
|
||||
metrics_controller=metrics_controller,
|
||||
|
||||
@@ -31,6 +31,8 @@ class MongoDB(SientiaMonitoring):
|
||||
ttl_index_seconds (int): TTL index duration in seconds
|
||||
logger (Logger): Application logger instance
|
||||
notification_handler (NotificationHandler): Notification management handler
|
||||
notification_queue_batch_size (int): Hard cap on documents fetched per
|
||||
`load_latest_data` run (SIENTIAPDE-2013). `0` means no limit.
|
||||
"""
|
||||
|
||||
def __init__(
|
||||
@@ -41,6 +43,7 @@ class MongoDB(SientiaMonitoring):
|
||||
logger: Logger,
|
||||
notification_handler: NotificationHandler,
|
||||
metrics_controller: MetricsController,
|
||||
notification_queue_batch_size: int = 0,
|
||||
):
|
||||
SientiaMonitoring.__init__(
|
||||
self,
|
||||
@@ -61,6 +64,7 @@ class MongoDB(SientiaMonitoring):
|
||||
)
|
||||
|
||||
self.ttl_index_seconds = ttl_index_seconds
|
||||
self.notification_queue_batch_size = notification_queue_batch_size
|
||||
|
||||
# Initialize MongoDB client here (omitted for brevity)
|
||||
logger.info('MongoDB connection initialized')
|
||||
@@ -447,6 +451,16 @@ class MongoDB(SientiaMonitoring):
|
||||
filtering by timestamp to enable incremental data processing. It
|
||||
handles connection management and provides comprehensive error reporting.
|
||||
|
||||
SIENTIAPDE-2013: the query is capped at ``notification_queue_batch_size``
|
||||
documents (hard cap per run, no drain loop) and sorted by ``timestamp``
|
||||
ascending, so a capped run always returns the *oldest* pending documents
|
||||
first. That matters because the caller advances its incremental cursor to
|
||||
the max timestamp of whatever this returns -- without the ascending sort,
|
||||
a capped batch could skip over older documents that never get picked up
|
||||
on a later run. This backstops a cold start, backlog buildup, or
|
||||
notification storm from fetching an unbounded (and potentially
|
||||
multi-megabyte) payload in one query.
|
||||
|
||||
Args:
|
||||
input_data (dict[str, Any]): Activity input parameters.
|
||||
Required fields:
|
||||
@@ -488,7 +502,13 @@ class MongoDB(SientiaMonitoring):
|
||||
|
||||
self.debug(f'Data filter: {data_filter}', metadata=metadata)
|
||||
|
||||
data = self.mongo_db_repository.find(collection_name, data_filter, metadata)
|
||||
data = self.mongo_db_repository.find(
|
||||
collection_name,
|
||||
data_filter,
|
||||
metadata,
|
||||
limit=self.notification_queue_batch_size,
|
||||
sort=[('timestamp', 1)],
|
||||
)
|
||||
|
||||
self.debug(f'Collected: {data}', metadata=metadata)
|
||||
|
||||
|
||||
@@ -21,7 +21,8 @@ def build_mongodb_config():
|
||||
Build MongoDB configuration from environment variables.
|
||||
|
||||
Returns:
|
||||
dict: MongoDB configuration with connection string, database name, and TTL index seconds.
|
||||
dict: MongoDB configuration with connection string, database name, TTL index seconds,
|
||||
and the notification queue's per-run batch size cap.
|
||||
"""
|
||||
username = getenv('MONGODB_USERNAME', 'root')
|
||||
password = getenv('MONGODB_PASSWORD', 'wKZDbMNU1c')
|
||||
@@ -32,6 +33,7 @@ def build_mongodb_config():
|
||||
'connection_string': connection_string,
|
||||
'database_name': getenv('MONGODB_DATABASE_NAME', 'sientia'),
|
||||
'ttl_index_seconds': int(getenv('MONGODB_TTL_INDEX_HOURS', '1')) * 3600,
|
||||
'notification_queue_batch_size': int(getenv('NOTIFICATION_QUEUE_BATCH_SIZE', '5000')),
|
||||
}
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user