{"id":329563,"date":"2024-05-24T22:38:06","date_gmt":"2024-05-24T22:38:06","guid":{"rendered":"https:\/\/www.baeldung.com\/?p=181972"},"modified":"2024-05-24T22:38:06","modified_gmt":"2024-05-24T22:38:06","slug":"consumer-processing-of-kafka-messages-with-delay","status":"publish","type":"post","link":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/2024\/05\/24\/consumer-processing-of-kafka-messages-with-delay\/","title":{"rendered":"Consumer Processing of Kafka Messages With Delay"},"content":{"rendered":"<p class=\"syndicated-attribution\"><meta name= \\\"keywords \\\" content= \\\"\u96fb\u5b50\u8a08\u7b97\u6a5f, \u6559\u80b2, IT \u96fb\u8166\u73ed,\u96fb\u8166\u88dc\u7fd2\uff0c \u96fb\u8166\u73ed\uff0c \u5bb6\u6559\uff0c \u79c1\u4eba\u8001\u5e2b\uff0c \u8cc7\u8a0a\u6280\u8853\uff0c \u7a0b\u5e8f\u8a2d\u8a08\uff0c \u96fb\u5b50\u8a08\u7b97\u6a5f\uff0c \u904a\u6232\uff0c \u860b\u679c\uff0c \u96fb\u5f71\uff0c \u8a08\u7b97\u6a5f\uff0c\u7de8\u78bc\uff0c Java\uff0c C\/C++\uff0c JavaScript\uff0c PHP\uff0c HTML\uff0c CSS\uff0c MySQL\uff0c mobile\uff0c Android\uff0c \u52d5\u6f2b\uff0c Python\uff0c teacher\uff0c \u88dc\u7fd2\uff0c \u96fb\u8166\u88dc\u7fd2 \u8cc7\u8a0a, \u7535\u5b50\u8ba1\u7b97\u673a, IT ,Game, apple, movie, Computer,student,Java,\u6559\u80b2, ,\u5b66\u751f, \u5b66\u4e60, learn, \u6559\u5b66,  Android, apple,anime, animation, \u4fe1\u606f\u6280\u672f, \u7a0b\u5e8f\u8bbe\u8ba1, \u79fb\u52a8\u7535\u8bdd, \u8cc7\u8a0a\u79d1\u6280,Game, Jeu, Juego,Call Of Duty ,\u4f7f\u547d\u53ec\u559a , \u6e38\u620f, \u7535\u5b50\u6e38\u620f,, \u591a\u4eba\u7535\u5b50\u6e38\u620f, \u7f51\u7edc\u6e38\u620f\uff0conline\uff0conline game, \u624b\u673a\u6e38\u620f, mobile \\\"><\/p>\n<p><img src=\"https:\/\/www.baeldung.com\/wp-content\/uploads\/2024\/05\/admin-ajax-2.png\" class=\"webfeedsFeaturedVisual wp-post-image\" alt=\"start here featured\" style=\"float: left; margin-right: 5px;\" decoding=\"async\" srcset=\"https:\/\/www.baeldung.com\/wp-content\/uploads\/2024\/05\/admin-ajax-2.png 600w, https:\/\/www.baeldung.com\/wp-content\/uploads\/2024\/05\/admin-ajax-2-300x157.png 300w, https:\/\/www.baeldung.com\/wp-content\/uploads\/2024\/05\/admin-ajax-2-100x52.png 100w\" sizes=\"(max-width: 580px) 100vw, 580px\" \/><\/p>\n<h2 id=\"bd-overview\" data-id=\"overview\">1. Overview<\/h2>\n<div class=\"bd-anchor\" id=\"overview\"><\/div>\n<p><a href=\"https:\/\/feeds.feedblitz.com\/~\/t\/0\/0\/baeldung\/~https:\/\/www.baeldung.com\/apache-kafka\">Apache Kafka<\/a> is an event streaming platform that collects, processes, stores, and integrates data at scale. Sometimes, we may want to delay the processing of messages from Kafka. An example is a customer order processing system designed to process orders after a delay of X seconds, accommodating cancellations within this timeframe.<\/p>\n<p>In this article, we&#8217;ll explore consumer processing of Kafka messages with delay using <a href=\"https:\/\/feeds.feedblitz.com\/~\/t\/0\/0\/baeldung\/~https:\/\/www.baeldung.com\/spring-kafka\">Spring Kafka<\/a>. Although Kafka doesn&#8217;t provide out-of-the-box support for the delayed consumption of messages, we&#8217;ll look at an alternative option for implementation.<\/p>\n<h2 id=\"bd-application-context\" data-id=\"application-context\">2. Application Context<\/h2>\n<div class=\"bd-anchor\" id=\"application-context\"><\/div>\n<p><strong>Kafka offers multiple ways to retry on errors. We&#8217;ll use this retry mechanism to delay the consumer processing of messages. Therefore, it&#8217;s worth understanding how <a href=\"https:\/\/feeds.feedblitz.com\/~\/t\/0\/0\/baeldung\/~https:\/\/www.baeldung.com\/spring-retry-kafka-consumer\">Kafka retry<\/a> works.<\/strong><\/p>\n<p>Let&#8217;s consider an order processing application where a customer can place an order on a UI. The user can cancel mistakenly placed orders within 10 seconds. These orders go to the Kafka topic <em>web.orders<\/em>, where our application processes them.<\/p>\n<p>An external service exposes the latest order status (<em>CREATED, ORDER_CONFIRMED, ORDER_PROCESSED, DELETED<\/em>). Our application needs to receive the message, wait for 10 seconds, and check with the external service to process the order if it&#8217;s in <em>CONFIRMED<\/em> status, i.e., the user hasn&#8217;t canceled it within the 10 seconds.<\/p>\n<p>For testing, the internal orders received from <em>web.orders.internal<\/em> shouldn&#8217;t be delayed.<\/p>\n<p>Let&#8217;s add a simple <em>Order<\/em> model that has <em>orderGeneratedDateTime<\/em> populated by the producer and <em>orderProcessedTime<\/em> populated by the consumer after a delayed duration:<\/p>\n<pre><code class=\"language-java\">@Data\r\n@Builder\r\n@AllArgsConstructor\r\n@NoArgsConstructor\r\npublic class Order {\r\n    private UUID orderId;\r\n    private LocalDateTime orderGeneratedDateTime;\r\n    private LocalDateTime orderProcessedTime;\r\n    private List&lt;String&gt; address;\r\n    private double price;\r\n}<\/code><\/pre>\n<h2 id=\"bd-kafka-listener-and-external-service\" data-id=\"kafka-listener-and-external-service\">3. Kafka Listener and External Service<\/h2>\n<div class=\"bd-anchor\" id=\"kafka-listener-and-external-service\"><\/div>\n<p>Next, <strong>we&#8217;ll add a listener for topic consumption and a service that exposes the status of the orders.<\/strong><\/p>\n<p>Let&#8217;s add a <em><a href=\"https:\/\/feeds.feedblitz.com\/~\/t\/0\/0\/baeldung\/~https:\/\/docs.spring.io\/spring-kafka\/reference\/kafka\/receiving-messages\/listener-annotation.html\">KafkaListener<\/a><\/em> which reads and processes messages from topics <em>web.orders<\/em> and <em>web.internal.orders<\/em> :<\/p>\n<pre><code class=\"language-java\">@RetryableTopic(attempts = &quot;1&quot;, include = KafkaBackoffException.class, dltStrategy = DltStrategy.NO_DLT)\r\n@KafkaListener(topics = { &quot;web.orders&quot;, &quot;web.internal.orders&quot; }, groupId = &quot;orders&quot;)\r\npublic void handleOrders(String order) throws JsonProcessingException {\r\n    Order orderDetails = objectMapper.readValue(order, Order.class);\r\n    OrderService.Status orderStatus = orderService.findStatusById(orderDetails.getOrderId());\r\n    if (orderStatus.equals(OrderService.Status.ORDER_CONFIRMED)) {\r\n        orderService.processOrder(orderDetails);\r\n    }\r\n}<\/code><\/pre>\n<p title=\"Class KafkaBackoffAwareMessageListenerAdapter\">It&#8217;s important to include <em>KafkaBackoffException<\/em> so that the listener allows retries. For simplicity, let&#8217;s consider that the external <em>OrderService<\/em> always returns the order status as <em>CONFIRMED. <\/em>Also, the <em>processOrder()<\/em> method sets the order processed time as the current time and saves the order into a <em>HashMap<\/em>:<\/p>\n<pre><code class=\"language-java\">@Service\r\npublic class OrderService {\r\n    HashMap&lt;UUID, Order&gt; orders = new HashMap&lt;&gt;();\r\n    public Status findStatusById(UUID orderId) {\r\n        return Status.ORDER_CONFIRMED;\r\n    }\r\n    public void processOrder(Order order) {\r\n        order.setOrderProcessedTime(LocalDateTime.now());\r\n        orders.put(order.getOrderId(), order);\r\n    }\r\n}<\/code><\/pre>\n<h2 id=\"bd-custom-delayed-message-listener\" data-id=\"custom-delayed-message-listener\">4. Custom Delayed Message Listener<\/h2>\n<div class=\"bd-anchor\" id=\"custom-delayed-message-listener\"><\/div>\n<p>Spring-Kafka comes up with the <a href=\"https:\/\/feeds.feedblitz.com\/~\/t\/0\/0\/baeldung\/~https:\/\/docs.spring.io\/spring-kafka\/docs\/current\/api\/org\/springframework\/kafka\/listener\/adapter\/KafkaBackoffAwareMessageListenerAdapter.html\"><em>KafkaBackoffAwareMessageListenerAdapter<\/em><\/a> which extends <em>AbstractAdaptableMessageListener<\/em> and implements <em>AcknowledgingConsumerAwareMessageListener<\/em>. <strong>This adapter examines the backoff <em>dueTimestamp<\/em> header and either backs off the message by invoking <em>KafkaConsumerBackoffManager<\/em> or retries the processing.<\/strong><\/p>\n<p>Let&#8217;s now implement the <em>DelayedMessageListenerAdapter <\/em>similar to <em>KafkaBackoffAwareMessageListenerAdapter<\/em>. This adapter should provide flexibility to configure delays per topic along with a default delay of <em>0<\/em> seconds:<\/p>\n<pre><code class=\"language-java\">public class DelayedMessageListenerAdapter&lt;K, V&gt; extends AbstractDelegatingMessageListenerAdapter&lt;MessageListener&lt;K, V&gt;&gt; \r\n  implements AcknowledgingConsumerAwareMessageListener&lt;K, V&gt; {\r\n    \/\/ Field declaration and constructor\r\n    public void setDelayForTopic(String topic, Duration delay) {\r\n        Objects.requireNonNull(topic, &quot;Topic cannot be null&quot;);\r\n        Objects.requireNonNull(delay, &quot;Delay cannot be null&quot;);\r\n        this.logger.debug(() -&gt; String.format(&quot;Setting delay %s for listener id %s&quot;, delay, this.listenerId));\r\n        this.delaysPerTopic.put(topic, delay);\r\n    }\r\n    public void setDefaultDelay(Duration delay) {\r\n        Objects.requireNonNull(delay, &quot;Delay cannot be null&quot;);\r\n        this.logger.debug(() -&gt; String.format(&quot;Setting delay %s for listener id %s&quot;, delay, this.listenerId));\r\n        this.defaultDelay = delay;\r\n    }\r\n    @Override\r\n    public void onMessage(ConsumerRecord&lt;K, V&gt; consumerRecord, Acknowledgment acknowledgment, Consumer&lt;?, ?&gt; consumer) throws KafkaBackoffException {\r\n        this.kafkaConsumerBackoffManager.backOffIfNecessary(createContext(consumerRecord,\r\n          consumerRecord.timestamp() + delaysPerTopic.getOrDefault(consumerRecord.topic(), this.defaultDelay)\r\n          .toMillis(), consumer));\r\n        invokeDelegateOnMessage(consumerRecord, acknowledgment, consumer);\r\n    }\r\n    private KafkaConsumerBackoffManager.Context createContext(ConsumerRecord&lt;K, V&gt; data, long nextExecutionTimestamp, Consumer&lt;?, ?&gt; consumer) {\r\n        return this.kafkaConsumerBackoffManager.createContext(nextExecutionTimestamp, \r\n          this.listenerId, \r\n          new TopicPartition(data.topic(), data.partition()), consumer);\r\n    }\r\n}<\/code><\/pre>\n<p>For every incoming message, this adapter first receives the record and checks the delay set for the topic. This will be set in the configuration, and if not set, it uses the default delay.<\/p>\n<p>The existing implementation of <em>KafkaConsumerBackoffManager#backOffIfNecessary <\/em>method checks the difference between the context record timestamp and the current timestamp.\u00a0If the difference is positive, showing no consumption due, the partition pauses and raises a <a href=\"https:\/\/feeds.feedblitz.com\/~\/t\/0\/0\/baeldung\/~https:\/\/docs.spring.io\/spring-kafka\/api\/org\/springframework\/kafka\/listener\/KafkaBackoffException.html\"><em>KafkaBackoffException<\/em><\/a>. Otherwise, it sends the record to the <em>KafkaListener<\/em> method for consumption.<\/p>\n<h2 id=\"bd-listener-configuration\" data-id=\"listener-configuration\">5. Listener Configuration<\/h2>\n<div class=\"bd-anchor\" id=\"listener-configuration\"><\/div>\n<p><strong>The <em><a href=\"https:\/\/feeds.feedblitz.com\/~\/t\/0\/0\/baeldung\/~https:\/\/docs.spring.io\/spring-kafka\/api\/org\/springframework\/kafka\/config\/ConcurrentKafkaListenerContainerFactory.html\">ConcurrentKafkaListenerContainerFactory<\/a><\/em> is the default implementation of Spring Kafka which is responsible for building containers for <em>KafkaListener<\/em>.<\/strong> It allows us to configure the number of concurrent <em>KafkaListener<\/em> instances. Each container can be considered a logical thread pool, where each thread is responsible for listening to messages from one or more Kafka topics.<\/p>\n<p>The <em>DelayedMessageListenerAdapter<\/em> needs to be configured with the listener by declaring a custom <em>ConcurrentKafkaListenerContainerFactory. <\/em>We can set the delay for specific topics like <em>web.orders<\/em> and also set a default delay of <em>0<\/em> for any other topics:<\/p>\n<pre><code class=\"language-java\">@Bean\r\npublic ConcurrentKafkaListenerContainerFactory&lt;Object, Object&gt; kafkaListenerContainerFactory(ConsumerFactory&lt;Object, Object&gt; consumerFactory, \r\n  ListenerContainerRegistry registry, TaskScheduler scheduler) {\r\n    ConcurrentKafkaListenerContainerFactory&lt;Object, Object&gt; factory = new ConcurrentKafkaListenerContainerFactory&lt;&gt;();\r\n    factory.setConsumerFactory(consumerFactory);\r\n    KafkaConsumerBackoffManager backOffManager = createBackOffManager(registry, scheduler);\r\n    factory.getContainerProperties()\r\n      .setAckMode(ContainerProperties.AckMode.RECORD);\r\n    factory.setContainerCustomizer(container -&gt; {\r\n        DelayedMessageListenerAdapter&lt;Object, Object&gt; delayedAdapter = wrapWithDelayedMessageListenerAdapter(backOffManager, container);\r\n        delayedAdapter.setDelayForTopic(&quot;web.orders&quot;, Duration.ofSeconds(10));\r\n        delayedAdapter.setDefaultDelay(Duration.ZERO);\r\n        container.setupMessageListener(delayedAdapter);\r\n    });\r\n    return factory;\r\n}\r\n@SuppressWarnings(&quot;unchecked&quot;)\r\nprivate DelayedMessageListenerAdapter&lt;Object, Object&gt; wrapWithDelayedMessageListenerAdapter(KafkaConsumerBackoffManager backOffManager, \r\n  ConcurrentMessageListenerContainer&lt;Object, Object&gt; container) {\r\n    return new DelayedMessageListenerAdapter&lt;&gt;((MessageListener&lt;Object, Object&gt;) container.getContainerProperties()\r\n      .getMessageListener(), backOffManager, container.getListenerId());\r\n}\r\nprivate ContainerPartitionPausingBackOffManager createBackOffManager(ListenerContainerRegistry registry, TaskScheduler scheduler) {\r\n    return new ContainerPartitionPausingBackOffManager(registry, \r\n      new ContainerPausingBackOffHandler(new ListenerContainerPauseService(registry, scheduler)));\r\n}<\/code><\/pre>\n<p>Notably, setting the acknowledgment mode at the <em>RECORD<\/em> level is essential to ensure that the consumer redelivers messages if an error happens during processing.<\/p>\n<p>Finally, we need to define a <em>TaskScheduler<\/em> bean to resume paused partitions after the delay duration and this scheduler needs to be injected into the <em>BackOffManager <\/em>which will be used by <em>DelayedMessageListenerAdapter<\/em>:<\/p>\n<pre><code class=\"language-java\">@Bean\r\npublic TaskScheduler taskScheduler() {\r\n    return new ThreadPoolTaskScheduler();\r\n}<\/code><\/pre>\n<h2 id=\"bd-testing\" data-id=\"testing\">6. Testing<\/h2>\n<div class=\"bd-anchor\" id=\"testing\"><\/div>\n<p>Let&#8217;s ensure orders on the <em>web.orders<\/em> topic undergo a 10-second delay before processing through testing:<\/p>\n<pre><code class=\"language-java\">@Test\r\nvoid givenKafkaBrokerExists_whenCreateOrderIsReceived_thenMessageShouldBeDelayed() throws Exception {\r\n    \/\/ Given\r\n    var orderId = UUID.randomUUID();\r\n    Order order = Order.builder()\r\n      .orderId(orderId)\r\n      .price(1.0)\r\n      .orderGeneratedDateTime(LocalDateTime.now())\r\n      .address(List.of(&quot;41 Felix Avenue, Luton&quot;))\r\n      .build();\r\n    String orderString = objectMapper.writeValueAsString(order);\r\n    ProducerRecord&lt;String, String&gt; record = new ProducerRecord&lt;&gt;(&quot;web.orders&quot;, orderString);\r\n    \r\n    \/\/ When\r\n    testKafkaProducer.send(record)\r\n      .get();\r\n    await().atMost(Duration.ofSeconds(1800))\r\n      .until(() -&gt; {\r\n          \/\/ then\r\n          Map&lt;UUID, Order&gt; orders = orderService.getOrders();\r\n          return orders != null &amp;&amp; orders.get(orderId) != null &amp;&amp; Duration.between(orders.get(orderId)\r\n              .getOrderGeneratedDateTime(), orders.get(orderId)\r\n              .getOrderProcessedTime())\r\n            .getSeconds() &gt;= 10;\r\n      });\r\n}<\/code><\/pre>\n<p>Next, we&#8217;ll test any orders to <em>web.internal.orders<\/em> follow a default delay of <em>0<\/em> seconds:<\/p>\n<pre><code class=\"language-java\">@Test\r\nvoid givenKafkaBrokerExists_whenCreateOrderIsReceivedForOtherTopics_thenMessageShouldNotBeDelayed() throws Exception {\r\n    \/\/ Given\r\n    var orderId = UUID.randomUUID();\r\n    Order order = Order.builder()\r\n      .orderId(orderId)\r\n      .price(1.0)\r\n      .orderGeneratedDateTime(LocalDateTime.now())\r\n      .address(List.of(&quot;41 Felix Avenue, Luton&quot;))\r\n      .build();\r\n    String orderString = objectMapper.writeValueAsString(order);\r\n    ProducerRecord&lt;String, String&gt; record = new ProducerRecord&lt;&gt;(&quot;web.internal.orders&quot;, orderString);\r\n    \r\n    \/\/ When\r\n    testKafkaProducer.send(record)\r\n      .get();\r\n    await().atMost(Duration.ofSeconds(1800))\r\n      .until(() -&gt; {\r\n          \/\/ Then\r\n          Map&lt;UUID, Order&gt; orders = orderService.getOrders();\r\n          System.out.println(&quot;Time....&quot; + Duration.between(orders.get(orderId)\r\n              .getOrderGeneratedDateTime(), orders.get(orderId)\r\n              .getOrderProcessedTime())\r\n            .getSeconds());\r\n          return orders != null &amp;&amp; orders.get(orderId) != null &amp;&amp; Duration.between(orders.get(orderId)\r\n              .getOrderGeneratedDateTime(), orders.get(orderId)\r\n              .getOrderProcessedTime())\r\n            .getSeconds() &lt;= 1;\r\n      });\r\n}<\/code><\/pre>\n<h2 id=\"bd-conclusion\" data-id=\"conclusion\">7. Conclusion<\/h2>\n<div class=\"bd-anchor\" id=\"conclusion\"><\/div>\n<p>In this tutorial, we explored how a Kafka consumer can delay processing messages by fixed intervals.<\/p>\n<p>We can modify the implementation to dynamically set processing delays by utilizing embedded message durations as part of the message.<\/p>\n<p>As always, the source code for the examples is available <a href=\"https:\/\/feeds.feedblitz.com\/~\/t\/0\/0\/baeldung\/~https:\/\/github.com\/eugenp\/tutorials\/tree\/master\/spring-kafka-3\">over on GitHub<\/a>.<\/p>\n<p><Img align=\"left\" border=\"0\" height=\"1\" width=\"1\" alt=\"\" style=\"border:0;float:left;margin:0;padding:0;width:1px!important;height:1px!important;\" hspace=\"0\" src=\"https:\/\/feeds.feedblitz.com\/~\/i\/897538346\/0\/baeldung\"><\/p>\n<div style=\"clear:both;padding-top:0.2em;\"><a title=\"Like on Facebook\" href=\"https:\/\/feeds.feedblitz.com\/_\/28\/897538346\/baeldung\"><img decoding=\"async\" height=\"20\" src=\"https:\/\/assets.feedblitz.com\/i\/fblike20.png\" style=\"border:0;margin:0;padding:0;\"><\/a>&#160;<a title=\"Pin it!\" href=\"https:\/\/feeds.feedblitz.com\/_\/29\/897538346\/baeldung,https%3A%2F%2Fwww.baeldung.com%2Fwp-content%2Fuploads%2F2024%2F05%2Fadmin-ajax-2.png\"><img decoding=\"async\" height=\"20\" src=\"https:\/\/assets.feedblitz.com\/i\/pinterest20.png\" style=\"border:0;margin:0;padding:0;\"><\/a>&#160;<a title=\"Post to X.com\" href=\"https:\/\/feeds.feedblitz.com\/_\/24\/897538346\/baeldung\"><img decoding=\"async\" height=\"20\" src=\"https:\/\/assets.feedblitz.com\/i\/x.png\" style=\"border:0;margin:0;padding:0;\"><\/a>&#160;<a title=\"Subscribe by email\" href=\"https:\/\/feeds.feedblitz.com\/_\/19\/897538346\/baeldung\"><img decoding=\"async\" height=\"20\" src=\"https:\/\/assets.feedblitz.com\/i\/email20.png\" style=\"border:0;margin:0;padding:0;\"><\/a>&#160;<a title=\"Subscribe by RSS\" href=\"https:\/\/feeds.feedblitz.com\/_\/20\/897538346\/baeldung\"><img decoding=\"async\" height=\"20\" src=\"https:\/\/assets.feedblitz.com\/i\/rss20.png\" style=\"border:0;margin:0;padding:0;\"><\/a>&#160;<a rel=\"NOFOLLOW\" title=\"View Comments\" href=\"https:\/\/www.baeldung.com\/kafka-consumer-processing-messages-delay#respond\"><img decoding=\"async\" height=\"20\" style=\"border:0;margin:0;padding:0;\" src=\"https:\/\/assets.feedblitz.com\/i\/comments20.png\"><\/a>&#160;<a title=\"Follow Comments via RSS\" href=\"https:\/\/www.baeldung.com\/kafka-consumer-processing-messages-delay\/feed\"><img decoding=\"async\" height=\"20\" style=\"border:0;margin:0;padding:0;\" src=\"https:\/\/assets.feedblitz.com\/i\/commentsrss20.png\"><\/a>&#160;<\/div>\n\n<p class=\"syndicated-attribution\"><figure class= \\\"wp-block-image alignnone \\\"><img src= \\\"http:\/\/itteacheritfreelance.hk\/test\/wordpress\/wp-content\/uploads\/2016\/05\/logo2-2.png\\\" alt=\\\"IT\u96fb\u8166\u88dc\u7fd2 java\u88dc\u7fd2 \u70ba\u5927\u5bb6\u914d\u5c0d\u96fb\u8166\u88dc\u7fd2,IT freelance, \u79c1\u4eba\u8001\u5e2b, PHP\u88dc\u7fd2,CSS\u88dc\u7fd2,XML,Java\u88dc\u7fd2,MySQL\u88dc\u7fd2,graphic design\u88dc\u7fd2,\u4e2d\u5c0f\u5b78ICT\u88dc\u7fd2,\u4e00\u5c0d\u4e00\u79c1\u4eba\u88dc\u7fd2\u548cFreelance\u81ea\u7531\u5de5\u4f5c\u914d\u5c0d\u3002\\\"\/><figcaption>\u7acb\u523b\u8a3b\u518a\u53ca\u5831\u540d\u96fb\u8166\u88dc\u7fd2\u8ab2\u7a0b\u5427!<\/figcaption><\/figure>\r\n<\/br>Find A Teacher Form:\r\n<\/br>https:\/\/docs.google.com\/forms\/d\/1vREBnX5n262umf4wU5U2pyTwvk9O-JrAgblA-wH9GFQ\/viewform?edit_requested=true#responses\r\n<\/br><\/br>Email:\r\n<\/br>public1989two@gmail.com<br><br><br><br><br><br><br>\r\n<a href=www.itsec.hk style=color:#FFFFFF;>www.itsec.hk<\/a><br>\r\n<a href=\\\"www.itsec.vip\\\" style=color:#FFFFFF;>www.itsec.vip<\/a><br>\r\n<a href=\\\"www.itseceu.uk\\\" style=color:#FFFFFF;>www.itseceu.uk<\/a><br><\/p>","protected":false},"excerpt":{"rendered":"<div class=\"mh-excerpt\"><p><img decoding=\"async\" src=\"https:\/\/www.baeldung.com\/wp-content\/uploads\/2024\/05\/admin-ajax-2.png\" class=\"webfeedsFeaturedVisual wp-post-image\" alt=\"start here featured\"><\/p>\n<p>Explore consumer processing of Kafka messages with delay using Spring Kafka.<\/p>\n<div><a title=\"Like on Facebook\" href=\"https:\/\/feeds.feedblitz.com\/_\/28\/897538346\/baeldung\"><img decoding=\"async\" height=\"20\" src=\"https:\/\/assets.feedblitz.com\/i\/fblike20.png\"><\/a>\u00a0<a title=\"Pin it!\" href=\"https:\/\/feeds.feedblitz.com\/_\/29\/897538346\/baeldung,https%3A%2F%2Fwww.baeldung.com%2Fwp-content%2Fuploads%2F2024%2F05%2Fadmin-ajax-2.png\"><img decoding=\"async\" height=\"20\" src=\"https:\/\/assets.feedblitz.com\/i\/pinterest20.png\"><\/a>\u00a0<a title=\"Post to X.com\" href=\"https:\/\/feeds.feedblitz.com\/_\/24\/897538346\/baeldung\"><img decoding=\"async\" height=\"20\" src=\"https:\/\/assets.feedblitz.com\/i\/x.png\"><\/a>\u00a0<a title=\"Subscribe by email\" href=\"https:\/\/feeds.feedblitz.com\/_\/19\/897538346\/baeldung\"><img decoding=\"async\" height=\"20\" src=\"https:\/\/assets.feedblitz.com\/i\/email20.png\"><\/a>\u00a0<a title=\"Subscribe by RSS\" href=\"https:\/\/feeds.feedblitz.com\/_\/20\/897538346\/baeldung\"><img decoding=\"async\" height=\"20\" src=\"https:\/\/assets.feedblitz.com\/i\/rss20.png\"><\/a>\u00a0<a rel=\"NOFOLLOW\" title=\"View Comments\" href=\"https:\/\/www.baeldung.com\/kafka-consumer-processing-messages-delay#respond\"><img decoding=\"async\" height=\"20\" src=\"https:\/\/assets.feedblitz.com\/i\/comments20.png\"><\/a>\u00a0<a title=\"Follow Comments via RSS\" href=\"https:\/\/www.baeldung.com\/kafka-consumer-processing-messages-delay\/feed\"><img decoding=\"async\" height=\"20\" src=\"https:\/\/assets.feedblitz.com\/i\/commentsrss20.png\"><\/a>\u00a0<\/div>\n<\/div>","protected":false},"author":1979,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"slim_seo":{"title":"Consumer Processing of Kafka Messages With Delay - ITTeacherITFreelance.hk","description":"Explore consumer processing of Kafka messages with delay using Spring Kafka. \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0 \u00a0"},"footnotes":""},"categories":[6,1307],"tags":[10803],"_links":{"self":[{"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/329563"}],"collection":[{"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/users\/1979"}],"replies":[{"embeddable":true,"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/comments?post=329563"}],"version-history":[{"count":1,"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/329563\/revisions"}],"predecessor-version":[{"id":329564,"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/posts\/329563\/revisions\/329564"}],"wp:attachment":[{"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/media?parent=329563"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/categories?post=329563"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/itteacheritfreelance.hk\/wordpress\/index.php\/wp-json\/wp\/v2\/tags?post=329563"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}