@@ -35,9 +35,10 @@ def __init__(self) -> None:
3535 self .should_finish = threading .Event ()
3636 self .flush_interval_seconds = 60
3737 self .events : t .List [Event ] = []
38+ # 4.5MB max uncompressed payload size, following <https://github.com/DataDog/datadog-ci-rb/pull/272>.
39+ self .max_payload_size = int (4.5 * 1024 * 1024 )
3840
3941 def put_event (self , event : Event ) -> None :
40- # TODO: compute/estimate payload size as events are inserted, and force a push once we reach a certain size.
4142 with self .lock :
4243 self .events .append (event )
4344
@@ -80,6 +81,22 @@ def flush(self) -> None:
8081 def _send_events (self , events : t .List [Event ]) -> None :
8182 pass
8283
84+ @abstractmethod
85+ def _encode_events (self , events : t .List [Event ]) -> bytes :
86+ pass
87+
88+ def _split_pack_events (self , events : t .List [Event ]) -> t .List [bytes ]:
89+ pack = self ._encode_events (events )
90+
91+ if len (pack ) > self .max_payload_size and len (events ) > 1 :
92+ del pack
93+ midpoint = len (events ) // 2
94+ packs = self ._split_pack_events (events [0 :midpoint ])
95+ packs += self ._split_pack_events (events [midpoint :])
96+ return packs
97+ else :
98+ return [pack ]
99+
83100
84101class TestOptWriter (BaseWriter ):
85102 __test__ = False
@@ -122,27 +139,36 @@ def put_item(self, item: TestItem[t.Any, t.Any]) -> None:
122139 event = self .serializers [type (item )](item )
123140 self .put_event (event )
124141
125- def _send_events (self , events : t .List [Event ]) -> None :
142+ def _encode_events (self , events : t .List [Event ]) -> bytes :
126143 payload = {
127144 "version" : 1 ,
128145 "metadata" : self .metadata ,
129146 "events" : events ,
130147 }
148+ return msgpack_packb (payload )
149+
150+ def _send_events (self , events : t .List [Event ]) -> None :
131151 with StopWatch () as serialization_time :
132- pack = msgpack_packb ( payload )
152+ packs = self . _split_pack_events ( events )
133153
134- result = self .connector .request (
135- "POST" , "/api/v2/citestcycle" , data = pack , headers = {"Content-Type" : "application/msgpack" }, send_gzip = True
136- )
154+ TelemetryAPI .get ().record_event_payload_serialization_seconds ("test_cycle" , serialization_time .elapsed ())
137155
138- TelemetryAPI .get ().record_event_payload (
139- endpoint = "test_cycle" ,
140- payload_size = len (pack ),
141- request_seconds = result .elapsed_seconds ,
142- events_count = len (events ),
143- serialization_seconds = serialization_time .elapsed (),
144- error = result .error_type ,
145- )
156+ for pack in packs :
157+ result = self .connector .request (
158+ "POST" ,
159+ "/api/v2/citestcycle" ,
160+ data = pack ,
161+ headers = {"Content-Type" : "application/msgpack" },
162+ send_gzip = True ,
163+ )
164+
165+ TelemetryAPI .get ().record_event_payload (
166+ endpoint = "test_cycle" ,
167+ payload_size = len (pack ),
168+ request_seconds = result .elapsed_seconds ,
169+ events_count = len (events ),
170+ error = result .error_type ,
171+ )
146172
147173
148174class TestCoverageWriter (BaseWriter ):
@@ -169,35 +195,40 @@ def put_coverage(self, test_run: TestRun, coverage_bitmaps: t.Iterable[t.Tuple[s
169195 )
170196 self .put_event (event )
171197
198+ def _encode_events (self , events : t .List [Event ]) -> bytes :
199+ return msgpack_packb ({"version" : 2 , "coverages" : events })
200+
172201 def _send_events (self , events : t .List [Event ]) -> None :
173202 with StopWatch () as serialization_time :
174- pack = msgpack_packb ({"version" : 2 , "coverages" : events })
175-
176- files = [
177- FileAttachment (
178- name = "coverage1" ,
179- filename = "coverage1.msgpack" ,
180- content_type = "application/msgpack" ,
181- data = pack ,
182- ),
183- FileAttachment (
184- name = "event" ,
185- filename = "event.json" ,
186- content_type = "application/json" ,
187- data = b'{"dummy":true}' ,
188- ),
189- ]
190-
191- result = self .connector .post_files ("/api/v2/citestcov" , files = files , send_gzip = True )
192-
193- TelemetryAPI .get ().record_event_payload (
194- endpoint = "code_coverage" ,
195- payload_size = len (pack ),
196- request_seconds = result .elapsed_seconds ,
197- events_count = len (events ),
198- serialization_seconds = serialization_time .elapsed (),
199- error = result .error_type ,
200- )
203+ packs = self ._split_pack_events (events )
204+
205+ TelemetryAPI .get ().record_event_payload_serialization_seconds ("code_coverage" , serialization_time .elapsed ())
206+
207+ for pack in packs :
208+ files = [
209+ FileAttachment (
210+ name = "coverage1" ,
211+ filename = "coverage1.msgpack" ,
212+ content_type = "application/msgpack" ,
213+ data = pack ,
214+ ),
215+ FileAttachment (
216+ name = "event" ,
217+ filename = "event.json" ,
218+ content_type = "application/json" ,
219+ data = b'{"dummy":true}' ,
220+ ),
221+ ]
222+
223+ result = self .connector .post_files ("/api/v2/citestcov" , files = files , send_gzip = True )
224+
225+ TelemetryAPI .get ().record_event_payload (
226+ endpoint = "code_coverage" ,
227+ payload_size = len (pack ),
228+ request_seconds = result .elapsed_seconds ,
229+ events_count = len (events ),
230+ error = result .error_type ,
231+ )
201232
202233
203234def serialize_test_run (test_run : TestRun ) -> Event :
0 commit comments