25
25
import uuid
26
26
import sys
27
27
import json
28
+ import gc
28
29
from copy import copy
29
30
30
31
try :
@@ -141,6 +142,9 @@ def verify_producer():
141
142
142
143
143
144
145
+ # Global variable to track garbage collection of suppressed on_delivery callbacks
146
+ DrOnlyTestSuccess_gced = 0
147
+
144
148
def test_producer_dr_only_error ():
145
149
"""
146
150
The C delivery.report.only.error configuration property
@@ -157,7 +161,7 @@ def test_producer_dr_only_error():
157
161
'broker.address.family' :'v4' ,
158
162
"delivery.report.only.error" :True })
159
163
160
- class DrOnlyTest (object ):
164
+ class DrOnlyTestErr (object ):
161
165
def __init__ (self ):
162
166
self .remaining = 1
163
167
@@ -167,28 +171,45 @@ def handle_err (self, err, msg):
167
171
assert err is not None
168
172
self .remaining -= 1
169
173
174
+ class DrOnlyTestSuccess (object ):
170
175
def handle_success (self , err , msg ):
171
176
""" This delivery handler should never get called """
172
177
# FIXME: Can we verify that it is actually garbage collected?
173
178
assert "GOOD:" in msg .value ().decode ('utf-8' )
174
179
assert err is None
175
180
assert False , "should never come here"
176
181
177
- state = DrOnlyTest ()
182
+ def __del__ (self ):
183
+ # Indicate that gc has hit this object.
184
+ global DrOnlyTestSuccess_gced
185
+ DrOnlyTestSuccess_gced = 1
178
186
179
187
print ('only.error: Verifying delivery.report.only.error' )
188
+
189
+ state = DrOnlyTestErr ()
180
190
p .produce (topic , "BAD: This message will make not make it" .encode ('utf-8' ),
181
191
partition = 99 , on_delivery = state .handle_err )
182
192
193
+ not_called_state = DrOnlyTestSuccess ()
183
194
p .produce (topic , "GOOD: This message will make make it" .encode ('utf-8' ),
184
- on_delivery = state .handle_success )
195
+ on_delivery = not_called_state .handle_success )
196
+
197
+ # Garbage collection should not kick in yet for not_called_state
198
+ # since there is a on_delivery reference to it.
199
+ not_called_state = None
200
+ gc .collect ()
201
+ global DrOnlyTestSuccess_gced
202
+ assert DrOnlyTestSuccess_gced == 0
185
203
186
- print ('only.error: Waiting for flush' )
204
+ print ('only.error: Waiting for flush of %d messages' % len ( p ) )
187
205
p .flush (10000 )
188
206
189
207
print ('only.error: Remaining messages now %d' % state .remaining )
190
208
assert state .remaining == 0
191
209
210
+ # Now with all messages flushed the reference to not_called_state should be gone.
211
+ gc .collect ()
212
+ assert DrOnlyTestSuccess_gced == 1
192
213
193
214
194
215
def verify_avro ():
0 commit comments