繁体   English   中英

将 Spring Cloud Stream 与 Kafka 一起使用时,如何正常关闭应用程序?

[英]How to perform a graceful application shutdown when using Spring Cloud Stream with Kafka?

我有一个使用 Spring Cloud Stream (v1.3.0) 和 Kafka (v1.1.6) 的 Spring Boot (v.1.57) 应用程序。 我希望能够优雅地关闭它,即在关闭时,所有流侦听器(即用 @StreamListener 注释)应该:

  1. 停止轮询新消息
  2. 完成他们的工作
  3. 将偏移量提交给 Kafka

我注意到 ContainerProperties 中有一个名为“shutdownTimeout”的属性(设置为默认值 10000 毫秒),因此我尝试通过像这样的反射扩展 ConcurrentKafkaListenerContainerFactoryConfigurer 类(因为它有 @ConditionalOnMissingBean 注释)将其修改为 30000:

@Slf4j
@Component
public class BehalfConcurrentKafkaListenerContainerFactoryConfigurer extends ConcurrentKafkaListenerContainerFactoryConfigurer {

    @Autowired
    private KafkaProperties kproperties;

    @Override
    public void configure(ConcurrentKafkaListenerContainerFactory<Object, Object> listenerContainerFactory,
                          ConsumerFactory<Object, Object> consumerFactory) {
        PropertyAccessor myAccessor = PropertyAccessorFactory.forDirectFieldAccess(this);
        myAccessor.setPropertyValue("properties", kproperties);

        ContainerProperties containerProperties = listenerContainerFactory
                .getContainerProperties();
        super.configure(listenerContainerFactory, consumerFactory);
        containerProperties.setShutdownTimeout(30000);
    }
}

但它没有成功。 还尝试将它 (shutdownTimeout: 30000) 放在 spring 云流绑定器设置下的 application.yml 中,但它再次没有帮助。

有什么方法可以控制关​​机过程并实现我的目标吗?

编辑

不再需要进行这种反射 hack; 只需将ListenerContainerCustomizer @Bean添加到应用程序上下文即可。 这里

EDIT_END

不再支持 spring-kafka 1.1.x; 您应该使用 1.3.9 和引导 1.5.x。

当前的 Boot 1.5.x 版本是 1.5.21。

您应该立即升级。

但是,所有这些项目都有更新的版本。

Spring Cloud Stream 不使用该工厂或引导属性来创建其容器; 它没有公开在容器上配置该属性的机制。

Spring Cloud Stream 2.1 添加了ListenerContainerCustomizer ,它允许您通过设置任何属性来自定义绑定容器。

我建议你升级到 Boot 2.1.6 和 Spring Cloud Stream Germantown (2.2.0)。

编辑

这有点黑客,但它应该可以工作,直到您可以升级到更新的流版本......

@SpringBootApplication
@EnableBinding(Sink.class)
public class So56883620Application {

    public static void main(String[] args) {
        SpringApplication.run(So56883620Application.class, args).close();
    }

    private final CountDownLatch latch = new CountDownLatch(1);

    @StreamListener(Sink.INPUT)
    public void listen(String in) throws InterruptedException {
        this.latch.countDown();
        System.out.println(in);
        Thread.sleep(6_000);
        System.out.println("exiting");
    }

    @Bean
    public ApplicationRunner runner(KafkaTemplate<byte[], byte[]> template) {
        return args -> {
            IntStream.range(0,2).forEach(i -> template.send("mytopic", ("foo" + i).getBytes()));
            // wait for listener to start
            this.latch.await(10, TimeUnit.SECONDS);
            System.out.println("Shutting down");
        };
    }

    @Bean
    public SmartLifecycle bindingFixer(BindingService bindingService) {
        return new SmartLifecycle() {

            @Override
            public int getPhase() {
                return Integer.MAX_VALUE;
            }

            @Override
            public void stop() {
                // no op
            }

            @Override
            public void start() {
                @SuppressWarnings("unchecked")
                Map<String, Binding<?>> consumers = (Map<String, Binding<?>>) new DirectFieldAccessor(bindingService)
                        .getPropertyValue("consumerBindings");
                @SuppressWarnings("unchecked")
                Binding<?> inputBinding = ((List<Binding<?>>) consumers.get("input")).get(0);
                ((AbstractMessageListenerContainer<?, ?>) new DirectFieldAccessor(inputBinding)
                        .getPropertyValue("lifecycle.messageListenerContainer"))
                                .getContainerProperties().setShutdownTimeout(30_000L);
            }

            @Override
            public boolean isRunning() {
                return false;
            }

            @Override
            public void stop(Runnable callback) {
                callback.run();
            }

            @Override
            public boolean isAutoStartup() {
                return true;
            }
        };
    }

}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM