0

I got the following stacktrace using quarkus smallrye reactive messaging with kafka :

2020-07-24 01:38:31,662 ERROR [io.sma.rea.mes.kafka] (executor-thread-870) SRMSG18207: Unable to dispatch message to Kafka: io.smallrye.mutiny.subscription.BackPressureFailure: Could not emit tick 211 due to lack of requests
        at io.smallrye.mutiny.operators.multi.builders.IntervalMulti$IntervalRunnable.run(IntervalMulti.java:83)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
        at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180)
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294)
        at org.jboss.threads.ContextClassLoaderSavingRunnable.run(ContextClassLoaderSavingRunnable.java:35)
        at org.jboss.threads.EnhancedQueueExecutor.safeRun(EnhancedQueueExecutor.java:2046)
        at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.doRunTask(EnhancedQueueExecutor.java:1578)
        at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1452)
        at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
        at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
        at java.lang.Thread.run(Thread.java:748)
        at org.jboss.threads.JBossThread.run(JBossThread.java:479)

So I ve read https://smallrye.io/smallrye-mutiny/#_how_do_i_control_the_back_pressure

According to the documentation I ve add BackPressure control.

Before :

@Outgoing( "eqs-crossing-xxx" )
    public Multi< EQSAlert > eqsCrossingXXX_XXX(){

        final String series = CrossingEnum.XXX_XXX.getSeries();
        final String equipment = CrossingEnum.XXX_XXX.getEquipment();

        final String vehicleRegex = vehicleRegexService.getRegexBySeries( series );

        log.info( "Incoming request for {} - {}",  series, equipment);
        log.info( "Vehicle regex : {}", vehicleRegex );

        return Multi
                .createFrom()
                .ticks()
                .every(
                        Duration.ofSeconds( poolingInterval )
                )
                .concatMap(i -> {
                    final Multi<CrossingState> crossingStateBySeriesAndEquipment = CrossingState.getCrossingStateBySeriesAndEquipment(client, series, equipment);

                    return crossingStateBySeriesAndEquipment.flatMap(crossingState ->
                            crossingState.isActive() ?
                                    EQSAlert.getEQSAlertBySeriesAndEquipment(
                                            client,
                                            series,
                                            vehicleRegex,
                                            equipment
                                    )
                                    :
                                    Multi.createFrom().empty()
                    );
                });
    }

After :

@Outgoing( "eqs-crossing-xxx" )
    public Multi< EQSAlert > eqsCrossingXXX_XXX(){

        final String series = CrossingEnum.XXX_XXX.getSeries();
        final String equipment = CrossingEnum.XXX_XXX.getEquipment();

        final String vehicleRegex = vehicleRegexService.getRegexBySeries( series );

        log.info( "Incoming request for {} - {}",  series, equipment);
        log.info( "Vehicle regex : {}", vehicleRegex );

        return Multi
                .createFrom()
                .ticks()
                .every(
                        Duration.ofSeconds( poolingInterval )
                )
                .onOverflow()
                .buffer(10)
                .concatMap(i -> {
                    final Multi<CrossingState> crossingStateBySeriesAndEquipment = CrossingState.getCrossingStateBySeriesAndEquipment(client, series, equipment);

                    return crossingStateBySeriesAndEquipment.flatMap(crossingState ->
                            crossingState.isActive() ?
                                    EQSAlert.getEQSAlertBySeriesAndEquipment(
                                            client,
                                            series,
                                            vehicleRegex,
                                            equipment
                                    )
                                    :
                                    Multi.createFrom().empty()
                    );
                });
    }

And now evrything is ok.

The purpose of my post is to understand why I need to do it ?

https://smallrye.io/smallrye-mutiny/apidocs/io/smallrye/mutiny/subscription/BackPressureStrategy.html

Why the buffer can't keep u ?

As you can see I do a simple sql function call every 5s (poolingInterval). The function returns some records (never more than 10 by pooling)

So the traffic is very low

May I have some words to understand the buffer management please.

Thank you

bdeweer
  • 135
  • 1
  • 14

1 Answers1

0

Your downstream can only consume a certain number of items per unit of time. It depends on what you are doing. By default, Kafka limits itself to 5 concurrent writes (you can configure it).

So, if you emit more, in an unbounded - not back-pressure aware - manner, the downstream cannot keep up. Adding a buffer of 10 items may handle small bumps, but it might not be enough.

drop is more radical; if the downstream cannot keep up, the items are simply discarded. dropPreviousItems is dropping the already received items.

Clement
  • 2,817
  • 1
  • 12
  • 11