3636AUTH_TIMEOUT_SECONDS : Final = 30.0
3737CONNECT_TIMEOUT_SECONDS : Final = 10.0
3838DBN_QUEUE_CAPACITY : Final = 2 ** 20
39+ DBN_QUEUE_LAG_THRESHOLD : Final = 128
40+ DBN_QUEUE_MAX_LAG_NS : Final = 1_000_000_000
41+ DBN_QUEUE_FULL_WARNING_INTERVAL_S : Final = 60.0
3942DEFAULT_REMOTE_PORT : Final = 13000
4043CLIENT_TIMEOUT_MARGIN_SECONDS : Final = 10
4144
@@ -48,6 +51,8 @@ class DBNQueue(queue.SimpleQueue): # type: ignore [type-arg]
4851 def __init__ (self ) -> None :
4952 super ().__init__ ()
5053 self ._enabled = threading .Event ()
54+ self ._front_ts_index : int | None = None
55+ self ._back_ts_index : int | None = None
5156
5257 def is_enabled (self ) -> bool :
5358 """
@@ -62,7 +67,16 @@ def is_full(self) -> bool:
6267 """
6368 Return True when the queue has reached capacity; False otherwise.
6469 """
65- return self .qsize () > DBN_QUEUE_CAPACITY
70+ if self .qsize () > DBN_QUEUE_CAPACITY :
71+ return True
72+ if (
73+ self .qsize () > DBN_QUEUE_LAG_THRESHOLD
74+ and self ._front_ts_index is not None
75+ and self ._back_ts_index is not None
76+ and self ._back_ts_index - self ._front_ts_index > DBN_QUEUE_MAX_LAG_NS
77+ ):
78+ return True
79+ return False
6680
6781 def enable (self ) -> None :
6882 """
@@ -106,6 +120,9 @@ def put(
106120
107121 """
108122 if self ._enabled .wait (timeout ):
123+ if self ._front_ts_index is None :
124+ self ._front_ts_index = item .ts_index
125+ self ._back_ts_index = item .ts_index
109126 return super ().put (item , block , timeout )
110127 if timeout is not None :
111128 raise BentoError (f"queue is not enabled after { timeout } second(s)" )
@@ -131,9 +148,34 @@ def put_nowait(self, item: DBNRecord) -> None:
131148
132149 """
133150 if self .is_enabled ():
151+ if self ._front_ts_index is None :
152+ self ._front_ts_index = item .ts_index
153+ self ._back_ts_index = item .ts_index
134154 return super ().put_nowait (item )
135155 raise BentoError ("queue is not enabled" )
136156
157+ def get (
158+ self ,
159+ block : bool = True ,
160+ timeout : float | None = None ,
161+ ) -> DBNRecord :
162+ record = super ().get (block , timeout )
163+ if self .empty ():
164+ self ._front_ts_index = None
165+ self ._back_ts_index = None
166+ else :
167+ self ._front_ts_index = record .ts_index
168+ return record
169+
170+ def get_nowait (self ) -> DBNRecord :
171+ record = super ().get_nowait ()
172+ if self .empty ():
173+ self ._front_ts_index = None
174+ self ._back_ts_index = None
175+ else :
176+ self ._front_ts_index = record .ts_index
177+ return record
178+
137179
138180@dataclasses .dataclass
139181class SessionMetadata :
@@ -225,6 +267,7 @@ def __init__(
225267 self ._user_streams = user_streams
226268 self ._last_ts_event : int | None = None
227269 self ._last_msg_loop_time : float = math .inf
270+ self ._last_queue_full_warning_t : float = - math .inf
228271
229272 def received_metadata (self , metadata : databento_dbn .Metadata ) -> None :
230273 if self ._metadata :
@@ -282,10 +325,13 @@ def _queue_for_iteration(self, record: DBNRecord) -> None:
282325 self ._dbn_queue .put (record )
283326 # DBNQueue has no max size; so check if it's above capacity, and if so, pause reading
284327 if self ._dbn_queue .is_full ():
285- logger .warning (
286- "record queue is full; %d record(s) to be processed" ,
287- self ._dbn_queue .qsize (),
288- )
328+ now = self ._loop .time ()
329+ if now - self ._last_queue_full_warning_t >= DBN_QUEUE_FULL_WARNING_INTERVAL_S :
330+ logger .warning (
331+ "record queue is full; %d record(s) to be processed" ,
332+ self ._dbn_queue .qsize (),
333+ )
334+ self ._last_queue_full_warning_t = now
289335 self .transport .pause_reading ()
290336
291337
0 commit comments