|
1 | 1 | /*
|
2 |
| - * Copyright 2002-2021 the original author or authors. |
| 2 | + * Copyright 2002-2022 the original author or authors. |
3 | 3 | *
|
4 | 4 | * Licensed under the Apache License, Version 2.0 (the "License");
|
5 | 5 | * you may not use this file except in compliance with the License.
|
|
77 | 77 | * @author Gary Russell
|
78 | 78 | * @author Artem Bilan
|
79 | 79 | * @author Alex Panchenko
|
| 80 | + * @author Mat Jaggard |
80 | 81 | *
|
81 | 82 | * @since 1.0
|
82 | 83 | */
|
@@ -605,59 +606,83 @@ private void waitForConsumersToStart(Set<AsyncMessageProcessingConsumer> process
|
605 | 606 |
|
606 | 607 | @Override
|
607 | 608 | protected void doShutdown() {
|
| 609 | + shutdownAndWaitOrCallback(null); |
| 610 | + } |
| 611 | + |
| 612 | + @Override |
| 613 | + public void stop(Runnable callback) { |
| 614 | + shutdownAndWaitOrCallback(() -> { |
| 615 | + setNotRunning(); |
| 616 | + callback.run(); |
| 617 | + }); |
| 618 | + } |
| 619 | + |
| 620 | + private void shutdownAndWaitOrCallback(@Nullable Runnable callback) { |
608 | 621 | Thread thread = this.containerStoppingForAbort.get();
|
609 | 622 | if (thread != null && !thread.equals(Thread.currentThread())) {
|
610 | 623 | logger.info("Shutdown ignored - container is stopping due to an aborted consumer");
|
611 | 624 | return;
|
612 | 625 | }
|
613 | 626 |
|
614 |
| - try { |
615 |
| - List<BlockingQueueConsumer> canceledConsumers = new ArrayList<>(); |
616 |
| - synchronized (this.consumersMonitor) { |
617 |
| - if (this.consumers != null) { |
618 |
| - Iterator<BlockingQueueConsumer> consumerIterator = this.consumers.iterator(); |
619 |
| - while (consumerIterator.hasNext()) { |
620 |
| - BlockingQueueConsumer consumer = consumerIterator.next(); |
621 |
| - consumer.basicCancel(true); |
622 |
| - canceledConsumers.add(consumer); |
623 |
| - consumerIterator.remove(); |
624 |
| - if (consumer.declaring) { |
625 |
| - consumer.thread.interrupt(); |
626 |
| - } |
| 627 | + List<BlockingQueueConsumer> canceledConsumers = new ArrayList<>(); |
| 628 | + synchronized (this.consumersMonitor) { |
| 629 | + if (this.consumers != null) { |
| 630 | + Iterator<BlockingQueueConsumer> consumerIterator = this.consumers.iterator(); |
| 631 | + while (consumerIterator.hasNext()) { |
| 632 | + BlockingQueueConsumer consumer = consumerIterator.next(); |
| 633 | + consumer.basicCancel(true); |
| 634 | + canceledConsumers.add(consumer); |
| 635 | + consumerIterator.remove(); |
| 636 | + if (consumer.declaring) { |
| 637 | + consumer.thread.interrupt(); |
627 | 638 | }
|
628 | 639 | }
|
| 640 | + } |
| 641 | + else { |
| 642 | + logger.info("Shutdown ignored - container is already stopped"); |
| 643 | + return; |
| 644 | + } |
| 645 | + } |
| 646 | + |
| 647 | + Runnable awaitShutdown = () -> { |
| 648 | + logger.info("Waiting for workers to finish."); |
| 649 | + try { |
| 650 | + boolean finished = this.cancellationLock.await(getShutdownTimeout(), TimeUnit.MILLISECONDS); |
| 651 | + if (finished) { |
| 652 | + logger.info("Successfully waited for workers to finish."); |
| 653 | + } |
629 | 654 | else {
|
630 |
| - logger.info("Shutdown ignored - container is already stopped"); |
631 |
| - return; |
| 655 | + logger.info("Workers not finished."); |
| 656 | + if (isForceCloseChannel()) { |
| 657 | + canceledConsumers.forEach(consumer -> { |
| 658 | + if (logger.isWarnEnabled()) { |
| 659 | + logger.warn("Closing channel for unresponsive consumer: " + consumer); |
| 660 | + } |
| 661 | + consumer.stop(); |
| 662 | + }); |
| 663 | + } |
632 | 664 | }
|
633 | 665 | }
|
634 |
| - logger.info("Waiting for workers to finish."); |
635 |
| - boolean finished = this.cancellationLock.await(getShutdownTimeout(), TimeUnit.MILLISECONDS); |
636 |
| - if (finished) { |
637 |
| - logger.info("Successfully waited for workers to finish."); |
| 666 | + catch (InterruptedException e) { |
| 667 | + Thread.currentThread().interrupt(); |
| 668 | + logger.warn("Interrupted waiting for workers. Continuing with shutdown."); |
638 | 669 | }
|
639 |
| - else { |
640 |
| - logger.info("Workers not finished."); |
641 |
| - if (isForceCloseChannel()) { |
642 |
| - canceledConsumers.forEach(consumer -> { |
643 |
| - if (logger.isWarnEnabled()) { |
644 |
| - logger.warn("Closing channel for unresponsive consumer: " + consumer); |
645 |
| - } |
646 |
| - consumer.stop(); |
647 |
| - }); |
648 |
| - } |
| 670 | + |
| 671 | + synchronized (this.consumersMonitor) { |
| 672 | + this.consumers = null; |
| 673 | + this.cancellationLock.deactivate(); |
649 | 674 | }
|
650 |
| - } |
651 |
| - catch (InterruptedException e) { |
652 |
| - Thread.currentThread().interrupt(); |
653 |
| - logger.warn("Interrupted waiting for workers. Continuing with shutdown."); |
654 |
| - } |
655 | 675 |
|
656 |
| - synchronized (this.consumersMonitor) { |
657 |
| - this.consumers = null; |
658 |
| - this.cancellationLock.deactivate(); |
| 676 | + if (callback != null) { |
| 677 | + callback.run(); |
| 678 | + } |
| 679 | + }; |
| 680 | + if (callback == null) { |
| 681 | + awaitShutdown.run(); |
| 682 | + } |
| 683 | + else { |
| 684 | + getTaskExecutor().execute(awaitShutdown); |
659 | 685 | }
|
660 |
| - |
661 | 686 | }
|
662 | 687 |
|
663 | 688 | private boolean isActive(BlockingQueueConsumer consumer) {
|
|
0 commit comments