title: Flink timer not executing on time
body: <p>This is a followup question to: <a href="https://stackoverflow.com/questions/54716107/flink-trigger-when-state-expires">Trigger when State expires</a></p>
  
  <p>I'm storing state of each incoming element in the stream and after the timer goes off, I remove the state. This is so that I can prevent duplicates from being processed until the element has timed out after which I can process the same element again.
  I</p>
  
  <p>I've written the following code to test timers but it seems that the timer is triggered after all 3 elements have gone through the first <code>ProcessFunction</code>.</p>
  
  <pre><code>public static void main(String[] args) throws Exception {
      StreamExecutionEnvironment streamEnv = StreamExecutionEnvironment.getExecutionEnvironment();
      streamEnv.setStreamTimeCharacteristic(TimeCharacteristic.IngestionTime);
      streamEnv.setParallelism(12);
  
      List&lt;Tuple2&lt;String, String&gt;&gt; inputList = new ArrayList&lt;&gt;();
      inputList.add(new Tuple2&lt;&gt;("Test", "test"));
      inputList.add(new Tuple2&lt;&gt;("Test", "test"));
      inputList.add(new Tuple2&lt;&gt;("Test", "test"));
  
      streamEnv.fromCollection(inputList).keyBy(0)
              .process(new ProcessFunction&lt;Tuple2&lt;String, String&gt;, Tuple2&lt;String, String&gt;&gt;() {
                  ValueState&lt;Integer&gt; occur;
  
                  @Override
                  public void open(Configuration parameters) throws Exception {
                      occur = getRuntimeContext().getState(new ValueStateDescriptor&lt;Integer&gt;("occurs", Integer.class, 0));
                  }
  
                  @Override
                  public void processElement(Tuple2&lt;String, String&gt; value, Context ctx, Collector&lt;Tuple2&lt;String, String&gt;&gt; out) throws Exception {
                      if (occur.value() &lt; 2) {
                          occur.update(occur.value() + 1);
                          out.collect(value);
                          LOGGER.info("[TEST] Outputting Tuple {}", value);
                      }
                      else {
                          Thread.sleep(10000);
                          LOGGER.info("[TEST] Outputting Tuple {}", value);
                          out.collect(value);
                      }
                  }
              })
              .keyBy(0)
              .process(new ProcessFunction&lt;Tuple2&lt;String, String&gt;, Tuple2&lt;String, String&gt;&gt;() {
                  ValueState&lt;Tuple2&lt;String, String&gt;&gt; storedTuple;
  
                  @Override
                  public void open(Configuration parameters) throws Exception {
                      storedTuple = getRuntimeContext().getState(new ValueStateDescriptor&lt;&gt;("storedTuple",
                              TypeInformation.of(new TypeHint&lt;Tuple2&lt;String, String&gt;&gt;() {})));
                  }
  
                  @Override
                  public void processElement(Tuple2&lt;String, String&gt; value, Context ctx, Collector&lt;Tuple2&lt;String, String&gt;&gt; out) throws Exception {
                      Tuple2&lt;String, String&gt; stored = storedTuple.value();
                      if (stored == null) {
                          LOGGER.info("[TEST] Storing Tuple {}", value);
                          storedTuple.update(value);
                          out.collect(value);
                          ctx.timerService().registerEventTimeTimer(ctx.timestamp() + 6000);
                      }
                  }
              }
  
              @Override
                  public void onTimer(long timestamp, OnTimerContext ctx, Collector&lt;Tuple2&lt;String, String&gt;&gt; out) throws Exception {
                      LOGGER.info("[TEST] Removing Tuple {}", storedTuple.value());
                      storedTuple.clear();
                  }    
              )
              .addSink(new CollectSink());
  
      streamEnv.execute("Testing");
      for (Tuple2&lt;String, String&gt; tup: CollectSink.values) {
          System.out.println(tup);
      }
  
  }
  
  private static class CollectSink implements SinkFunction&lt;Tuple2&lt;String, String&gt;&gt; {
  
      static final List&lt;Tuple2&lt;String, String&gt;&gt; values = new ArrayList&lt;&gt;();
  
      @Override
      public synchronized void invoke(Tuple2&lt;String, String&gt; value) throws Exception {
          values.add(value);
      }
  }
  </code></pre>
  
  <p>I have an input list with 3 duplicate elements. In the first <code>ProcessFunction</code> I send the first two elements as is but delay the 3rd element by 10 seconds.</p>
  
  <p>In the second <code>ProcessFunction</code> it filters the element based on whether the state is stored for it or not. As expected, the first element gets stored and sent onwards and the second element isn't as the state already exists. For the first element, apart from sending it on, I also set a timer for 6 seconds so that the state is cleared after the timer is triggered. </p>
  
  <p>Now the third element is sent on after 10 seconds which means that the 6 second trigger should have already cleared the state. However, the third element is also being processed before the timer is triggered. I can also see the output as containing only 1 copy of the Tuple even though I'm expected 2 copies.</p>
  
  <p>I've added some logging to give a better idea of the execution times.</p>
  
  <pre><code>[2019-02-19 14:11:48,891] [Process (1/12)] INFO  FlinkTest - [TEST] Outputting Tuple (Test,test)
  [2019-02-19 14:11:48,891] [Process (1/12)] INFO  FlinkTest - [TEST] Outputting Tuple (Test,test)
  [2019-02-19 14:11:48,943] [Process -&gt; Sink: Unnamed (1/12)] INFO  FlinkTest - [TEST] Storing Tuple (Test,test)
  [2019-02-19 14:11:58,891] [Process (1/12)] INFO  FlinkTest - [TEST] Outputting Tuple (Test,test)
  [2019-02-19 14:11:58,896] [Process -&gt; Sink: Unnamed (1/12)] INFO  FlinkTest - [TEST] Removing Tuple (Test,test)
  </code></pre>
  
  <p>You can see that the first two tuples are emitted together as expected followed by a 10 second delay after which the 3rd tuple is emitted. Now the <code>Removing Tuple</code> occurs after the 10 seconds even though it was triggered to occur after 6 seconds of the first tuple coming in.</p>