@@ -166,24 +166,37 @@ declare(XName, Type, Durable, AutoDelete, Internal, Args) ->
166
166
XT = type_to_module (Type ),
167
167
% % We want to upset things if it isn't ok
168
168
ok = XT :validate (X ),
169
- rabbit_misc :execute_mnesia_transaction (
170
- fun () ->
171
- case mnesia :wread ({rabbit_exchange , XName }) of
172
- [] ->
173
- {new , store (X )};
174
- [ExistingX ] ->
175
- {existing , ExistingX }
176
- end
177
- end ,
178
- fun ({new , Exchange }, Tx ) ->
179
- ok = callback (X , create , map_create_tx (Tx ), [Exchange ]),
180
- rabbit_event :notify_if (not Tx , exchange_created , info (Exchange )),
181
- Exchange ;
182
- ({existing , Exchange }, _Tx ) ->
183
- Exchange ;
184
- (Err , _Tx ) ->
185
- Err
186
- end ).
169
+ % % Avoid a channel exception if there's a race condition
170
+ % % with an exchange.delete operation.
171
+ % %
172
+ % % See rabbitmq/rabbitmq-federation#7.
173
+ case rabbit_runtime_parameters :lookup (XName # resource .virtual_host ,
174
+ ? EXCHANGE_DELETE_IN_PROGRESS_COMPONENT ,
175
+ XName # resource .name ) of
176
+ not_found ->
177
+ rabbit_misc :execute_mnesia_transaction (
178
+ fun () ->
179
+ case mnesia :wread ({rabbit_exchange , XName }) of
180
+ [] ->
181
+ {new , store (X )};
182
+ [ExistingX ] ->
183
+ {existing , ExistingX }
184
+ end
185
+ end ,
186
+ fun ({new , Exchange }, Tx ) ->
187
+ ok = callback (X , create , map_create_tx (Tx ), [Exchange ]),
188
+ rabbit_event :notify_if (not Tx , exchange_created , info (Exchange )),
189
+ Exchange ;
190
+ ({existing , Exchange }, _Tx ) ->
191
+ Exchange ;
192
+ (Err , _Tx ) ->
193
+ Err
194
+ end );
195
+ _ ->
196
+ rabbit_log :warning (" ignoring exchange.declare for exchange ~p ,
197
+ exchange.delete in progress~n ." , [XName ]),
198
+ X
199
+ end .
187
200
188
201
map_create_tx (true ) -> transaction ;
189
202
map_create_tx (false ) -> none .
@@ -427,18 +440,31 @@ delete(XName, IfUnused) ->
427
440
true -> fun conditional_delete /2 ;
428
441
false -> fun unconditional_delete /2
429
442
end ,
430
- call_with_exchange (
431
- XName ,
432
- fun (X ) ->
433
- case Fun (X , false ) of
434
- {deleted , X , Bs , Deletions } ->
435
- rabbit_binding :process_deletions (
436
- rabbit_binding :add_deletion (
437
- XName , {X , deleted , Bs }, Deletions ));
438
- {error , _InUseOrNotFound } = E ->
439
- rabbit_misc :const (E )
440
- end
441
- end ).
443
+ try
444
+ % % guard exchange.declare operations from failing when there's
445
+ % % a race condition between it and an exchange.delete.
446
+ % %
447
+ % % see rabbitmq/rabbitmq-federation#7
448
+ rabbit_runtime_parameters :set (XName # resource .virtual_host ,
449
+ ? EXCHANGE_DELETE_IN_PROGRESS_COMPONENT ,
450
+ XName # resource .name , true , none ),
451
+ call_with_exchange (
452
+ XName ,
453
+ fun (X ) ->
454
+ case Fun (X , false ) of
455
+ {deleted , X , Bs , Deletions } ->
456
+ rabbit_binding :process_deletions (
457
+ rabbit_binding :add_deletion (
458
+ XName , {X , deleted , Bs }, Deletions ));
459
+ {error , _InUseOrNotFound } = E ->
460
+ rabbit_misc :const (E )
461
+ end
462
+ end )
463
+ after
464
+ rabbit_runtime_parameters :clear (XName # resource .virtual_host ,
465
+ ? EXCHANGE_DELETE_IN_PROGRESS_COMPONENT ,
466
+ XName # resource .name )
467
+ end .
442
468
443
469
validate_binding (X = # exchange {type = XType }, Binding ) ->
444
470
Module = type_to_module (XType ),
0 commit comments