Repository: vert-x3/vertx-web
Issue: SessionHandler doesn't callback the handler of method flush in some cases

### Questions

SessionHandler doesn't callback the handler of method flush in some cases, leaving some user defined actions uncomplished in the handler.

### Version

vertx-web 3.9.12

### Context

Hi, we are developing website with Vert.x framework. When we tested the session feature based on the Vert.x `SessionHandler`, we find that sometimes the HTTP response has reached the browser while the session storage action is not finished.(We extended the `SessionStore` to put session into our cache server, sometime it may not act quickly) The root cause is the default logic of Vert.x `SessionHandler` is to flush session in the "HeadersEndHandler", and it does not ensure the response is sent after the session is flushed properly.

After searching some issues, we find this is the expected behavior. So we decide to run the `flush` method manually and write the response after the flush action is done. But we find the `flush` method of `SessionHandlerImpl` does not always callback the `handler`. The `handler` are only called back when the session is actually stored. If the response indicates error(status code 4xx/5xx) or the session is not touched or some other cases, the session will not be actually written into the `SessionStore` and the `handler` is not called.

This is a problem for those who want to do something after the session flush procedure ends. Because in some cases, the "end" is never shown to the caller of `flush` method.

### Do you have a reproducer?

Here is a reproducer:

```java
public class Demo {

    private static Vertx vertx = Vertx.vertx();

    private static int flag = 0;

    public static void main(String[] args) {
        final HttpServer httpServer = vertx.createHttpServer(new HttpServerOptions()
            .setIdleTimeout(10));
        final Router router = Router.router(vertx);
        final SessionHandler sessionHandler = SessionHandler.create(LocalSessionStore.create(vertx))
            .setSessionTimeout(10_000)
            .setLazySession(true);

        router.route().handler(sessionHandler);
        router.route().handler(ctx -> {
            System.out.println("get request");

            final HttpServerResponse response = ctx.response();
            ctx.session();
            if ((++flag & 1) == 0) {
                response.setStatusCode(500);
            } else {
                response.setStatusCode(200);
            }

            sessionHandler.flush(ctx, asyncResult -> {
                System.out.println("get session flush result: " + asyncResult.succeeded());
                response.putHeader("Content-Type", "text/plain");
                response.end("Hello World!");
                ctx.next();
            });
        });
        httpServer.requestHandler(router).listen(9999);
    }
}
```

Only the vertx-web dependency is needed for this demo.

### Steps to reproduce

1. run the demo above
2. curl `http://localhost:9999/`

I've made the server response `200` and `500` alternately. And when 200 is returned, the client will get response instantly, while when 500 should be returned, the server will hang the connection until the connection idle timed out.

### Extra

I'm not sure whether this is the expected behavior of `SessionHandler`. But I guess people who want to ensure the order between "flush session" and some "finish action" may be troubled by this behavior. Is it possible to fix this problem?

Looking forward to your reply, and thank you very much.

Changed files:
vertx-web/src/main/java/io/vertx/ext/web/handler/impl/SessionHandlerImpl.java, vertx-web/src/test/java/io/vertx/ext/web/sstore/LocalSessionHandlerTest.java

diff --git a/vertx-web/src/main/java/io/vertx/ext/web/handler/impl/SessionHandlerImpl.java b/vertx-web/src/main/java/io/vertx/ext/web/handler/impl/SessionHandlerImpl.java
index 40d6efbdc..e07b7ac85 100644
--- a/vertx-web/src/main/java/io/vertx/ext/web/handler/impl/SessionHandlerImpl.java
+++ b/vertx-web/src/main/java/io/vertx/ext/web/handler/impl/SessionHandlerImpl.java
@@ -238,6 +238,8 @@ public class SessionHandlerImpl implements SessionHandler {
             }
           });
         }
+      } else {
+        handler.handle(Future.failedFuture("Skipping session store: ignoreStatus || (currentStatusCode >= 200 && currentStatusCode < 400)"));
       }
     } else {
       if (!cookieless) {
diff --git a/vertx-web/src/test/java/io/vertx/ext/web/sstore/LocalSessionHandlerTest.java b/vertx-web/src/test/java/io/vertx/ext/web/sstore/LocalSessionHandlerTest.java
index 9b9fb7112..8b4948308 100644
--- a/vertx-web/src/test/java/io/vertx/ext/web/sstore/LocalSessionHandlerTest.java
+++ b/vertx-web/src/test/java/io/vertx/ext/web/sstore/LocalSessionHandlerTest.java
@@ -16,6 +16,8 @@
 
 package io.vertx.ext.web.sstore;
 
+import io.vertx.core.http.HttpMethod;
+import io.vertx.ext.web.handler.SessionHandler;
 import io.vertx.ext.web.handler.SessionHandlerTestBase;
 import org.junit.Test;
 
@@ -34,4 +36,25 @@ public class LocalSessionHandlerTest extends SessionHandlerTestBase {
   public void testRetryTimeout() throws Exception {
     assertTrue(doTestSessionRetryTimeout() < 3000);
   }
+
+  @Test
+  public void test2123() throws Exception {
+    SessionHandler sessionHandler = SessionHandler.create(LocalSessionStore.create(vertx))
+      .setSessionTimeout(10_000)
+      .setLazySession(true);
+
+    router.clear();
+
+    router.route().handler(sessionHandler);
+    router.route().handler(ctx -> {
+      ctx.session();
+      ctx.response().setStatusCode(500);
+      sessionHandler.flush(ctx, asyncResult -> {
+        assertTrue(asyncResult.failed());
+        ctx.end();
+      });
+    });
+
+    testRequest(HttpMethod.GET, "/", 500, "Internal Server Error");
+  }
 }