2222DEFAULT_BATCH_SIZE = 1000
2323
2424
25- class _ImmediatePublishBatch :
26- """Transport-neutral batch that retains immediate publication."""
27-
28- def __init__ (self , channel ):
29- self .channel = channel
30-
31- def publish (self , message , ** kwargs ):
32- return self .channel .basic_publish (message , ** kwargs )
33-
34- def flush (self ):
35- """Flush buffered messages (there are none)."""
36-
37- def discard (self ):
38- """Discard buffered messages (there are none)."""
39-
40- def close (self ):
41- """Release batch resources (there are none)."""
42-
43-
4425class _ProducerBatchState :
4526 """State shared by nested batch contexts in one producer thread."""
4627
4728 def __init__ (self , max_size ):
4829 self .max_size = max_size
4930 self .aborted = False
5031 self .session = None
32+ self .immediate = False
5133
5234 def _get_session (self , channel ):
35+ if self .immediate :
36+ return None
5337 if self .session is None :
5438 create_batch = getattr (channel , 'create_publish_batch' , None )
55- self . session = (
56- create_batch ( max_size = self . max_size )
57- if create_batch is not None
58- else _ImmediatePublishBatch ( channel )
59- )
39+ supports_batch = getattr ( channel , 'supports_batch_publish' , True )
40+ if create_batch is None or not supports_batch :
41+ self . immediate = True
42+ return None
43+ self . session = create_batch ( max_size = self . max_size )
6044 elif self .session .channel is not channel :
6145 raise RuntimeError (
6246 'Producer channel changed while a publish batch was active' ,
@@ -66,7 +50,10 @@ def _get_session(self, channel):
6650 def publish (self , channel , message , ** kwargs ):
6751 if self .aborted :
6852 raise RuntimeError ('Cannot publish through an aborted batch' )
69- return self ._get_session (channel ).publish (message , ** kwargs )
53+ session = self ._get_session (channel )
54+ if session is None :
55+ return channel .basic_publish (message , ** kwargs )
56+ return session .publish (message , ** kwargs )
7057
7158 def flush (self ):
7259 if self .aborted :
@@ -116,19 +103,33 @@ def __exit__(self, exc_type, exc_value, traceback):
116103 if state is None :
117104 return None
118105
106+ cleanup_error = None
119107 try :
120- if exc_type is not None :
121- state .abort ()
122-
123108 if self .is_outermost :
124109 del self .producer ._batch_local .current
110+
111+ if exc_type is not None :
125112 try :
126- if exc_type is None and not state .aborted :
113+ state .abort ()
114+ except BaseException as exc :
115+ cleanup_error = exc
116+
117+ if self .is_outermost :
118+ if exc_type is None and not state .aborted :
119+ try :
127120 state .flush ()
128- finally :
121+ except BaseException as exc :
122+ cleanup_error = exc
123+ try :
129124 state .close ()
125+ except BaseException as exc :
126+ if cleanup_error is None :
127+ cleanup_error = exc
130128 finally :
131129 self .active = False
130+
131+ if exc_type is None and cleanup_error is not None :
132+ raise cleanup_error
132133 return None
133134
134135 def flush (self ):
@@ -233,9 +234,23 @@ def supports_batch_publish(self):
233234 if connection is None :
234235 return False
235236 try :
236- return connection .transport .implements .batch_publish
237+ transport_support = connection .transport .implements .batch_publish
237238 except AttributeError :
238239 return False
240+ channel = self ._channel
241+ if channel is not None and not isinstance (channel , ChannelPromise ):
242+ configured_support = getattr (
243+ channel ,
244+ 'supports_batch_publish' ,
245+ transport_support ,
246+ )
247+ else :
248+ configured_support = getattr (
249+ connection .transport ,
250+ 'supports_batch_publish' ,
251+ transport_support ,
252+ )
253+ return bool (transport_support and configured_support )
239254
240255 def batch (self , max_size = DEFAULT_BATCH_SIZE ):
241256 """Group normal :meth:`publish` calls into transport-owned batches.
0 commit comments