vert-x3 / vertx-virtual-threads-incubator

Vert.x virtual threads incubator
118 stars 9 forks source link

Abstract virtual thread verticle draft implementation #13

Open doctorpangloss opened 11 months ago

doctorpangloss commented 11 months ago

Describe the feature

This is a starting point for implementing an abstract virtual thread verticle. It works very well for me in production.

Use cases

All handlers created in the verticle's start will themselves run within virtual threads, which is excellent! This makes interacting with blocking Java APIs seamless.

Contribution

Here's my code that I have been using:

package com.hiddenswitch.framework.virtual.concurrent;

import io.vertx.await.impl.EventLoopScheduler;
import io.vertx.await.impl.VirtualThreadContext;
import io.vertx.core.AbstractVerticle;
import io.vertx.core.Context;
import io.vertx.core.Promise;
import io.vertx.core.Vertx;
import io.vertx.core.impl.ContextInternal;
import io.vertx.core.impl.VertxInternal;

public abstract class AbstractVirtualThreadVerticle extends AbstractVerticle {

    private Context startingContext;
    private Context stoppingContext;

    @Override
    public final void init(Vertx vertx1, Context context1) {
        super.init(vertx1, context1);

        var context = (ContextInternal) context1;
        var scheduler = new EventLoopScheduler(context.nettyEventLoop());
        var vertx = (VertxInternal) vertx1;
        this.context = new VirtualThreadContext(vertx, context.nettyEventLoop(), vertx.getInternalWorkerPool(), vertx.getWorkerPool(), scheduler, context.getDeployment(), context.closeFuture(), Thread.currentThread().getContextClassLoader());
    }

    @Override
    public final void start() throws Exception {
    }

    @Override
    public final void stop() throws Exception {
    }

    @Override
    public final void start(Promise<Void> startPromise) throws Exception {
        this.startingContext = Vertx.currentContext();
        context.runOnContext(v -> {
            try {
                startVirtual();
                startingContext.runOnContext(v2 -> startPromise.complete());
            } catch (Throwable t) {
                startingContext.runOnContext(v2 -> startPromise.fail(t));
            }
        });
    }

    @Override
    public final void stop(Promise<Void> stopPromise) throws Exception {
        this.stoppingContext = Vertx.currentContext();
        context.runOnContext(v -> {
            try {
                stopVirtual();
                stoppingContext.runOnContext(v2 -> stopPromise.complete());
            } catch (Throwable t) {
                stoppingContext.runOnContext(v2 -> stopPromise.fail(t));
            }
        });
    }

    public void startVirtual() throws Exception {
    }

    public void stopVirtual() throws Exception {
    }

    protected Context startingContext() {
        return startingContext;
    }

    protected Context stoppingContext() {
        return stoppingContext;
    }
}

users should override startVirtual and stopVirtual with await on Vertx Futures. That's it.