diff --git a/api/src/main/java/telegram/files/AutoDownloadVerticle.java b/api/src/main/java/telegram/files/AutoDownloadVerticle.java index dc43307..0483bee 100644 --- a/api/src/main/java/telegram/files/AutoDownloadVerticle.java +++ b/api/src/main/java/telegram/files/AutoDownloadVerticle.java @@ -68,7 +68,11 @@ public class AutoDownloadVerticle extends AbstractVerticle { @Override public void stop(Promise stopPromise) { - saveAutoRecords().onComplete(stopPromise); + saveAutoRecords() + .onComplete(r -> { + log.info("Auto download verticle stopped!"); + stopPromise.complete(); + }); } private Future initAutoDownload() { @@ -123,7 +127,6 @@ public class AutoDownloadVerticle extends AbstractVerticle { autoRecords.items.forEach(settingAutoRecords::add); return DataVerticle.settingRepository.createOrUpdate(SettingKey.autoDownload.name(), Json.encode(settingAutoRecords)); }) - .onSuccess(v -> log.info("Save auto records success!")) .onFailure(e -> log.error("Save auto records failed!", e)) .mapEmpty(); } diff --git a/api/src/main/java/telegram/files/DataVerticle.java b/api/src/main/java/telegram/files/DataVerticle.java index d6bb2d7..513d100 100644 --- a/api/src/main/java/telegram/files/DataVerticle.java +++ b/api/src/main/java/telegram/files/DataVerticle.java @@ -57,10 +57,16 @@ public class DataVerticle extends AbstractVerticle { } @Override - public void stop() throws Exception { + public void stop(Promise stopPromise) throws Exception { if (pool != null) { - pool.close(); - log.debug("Database closed"); + pool.close().onComplete(r -> { + stopPromise.complete(); + if (r.succeeded()) { + log.debug("Data verticle stopped!"); + } else { + log.error("Failed to close data verticle: %s".formatted(r.cause().getMessage())); + } + }); } } diff --git a/api/src/main/java/telegram/files/HttpVerticle.java b/api/src/main/java/telegram/files/HttpVerticle.java index 2c9f5ac..3c74a73 100644 --- a/api/src/main/java/telegram/files/HttpVerticle.java +++ b/api/src/main/java/telegram/files/HttpVerticle.java @@ -43,6 +43,8 @@ public class HttpVerticle extends AbstractVerticle { // session id -> telegram verticle private final Map sessionTelegramVerticles = new ConcurrentHashMap<>(); + private AutoDownloadVerticle autoDownloadVerticle; + private static final String SESSION_COOKIE_NAME = "tf"; @Override @@ -54,6 +56,11 @@ public class HttpVerticle extends AbstractVerticle { .onFailure(startPromise::fail); } + @Override + public void stop() { + log.info("Http verticle stopped!"); + } + public Future initHttpServer() { int port = config().getInteger("http.port", 8080); HttpServerOptions options = new HttpServerOptions() @@ -196,7 +203,8 @@ public class HttpVerticle extends AbstractVerticle { } public Future initAutoDownloadVerticle() { - return vertx.deployVerticle(new AutoDownloadVerticle(), new DeploymentOptions() + autoDownloadVerticle = new AutoDownloadVerticle(); + return vertx.deployVerticle(autoDownloadVerticle, new DeploymentOptions() .setThreadingModel(ThreadingModel.VIRTUAL_THREAD) ) .mapEmpty(); @@ -306,10 +314,12 @@ public class HttpVerticle extends AbstractVerticle { return; } TelegramVerticle telegramVerticle = telegramVerticleOptional.get(); - telegramVerticle.delete(); - telegramVerticles.remove(telegramVerticle); - sessionTelegramVerticles.entrySet().removeIf(e -> e.getValue().equals(telegramVerticle)); - ctx.end(); + telegramVerticle.close(true) + .onSuccess(r -> { + telegramVerticles.remove(telegramVerticle); + sessionTelegramVerticles.entrySet().removeIf(e -> e.getValue().equals(telegramVerticle)); + ctx.end(); + }); } private void handleTelegrams(RoutingContext ctx) { diff --git a/api/src/main/java/telegram/files/Start.java b/api/src/main/java/telegram/files/Start.java index 8efbbe8..d0d3912 100644 --- a/api/src/main/java/telegram/files/Start.java +++ b/api/src/main/java/telegram/files/Start.java @@ -4,27 +4,80 @@ import cn.hutool.log.Log; import cn.hutool.log.LogFactory; import io.vertx.core.Vertx; +import java.util.concurrent.CountDownLatch; + public class Start { private static final Log log = LogFactory.get(); public static final String VERSION = "0.1.5"; - public static void main(String[] args) { - Vertx vertx = Vertx.vertx(); - Runtime.getRuntime().addShutdownHook(new Thread(() -> { - vertx.close().onComplete(res -> { - if (res.succeeded()) { - log.info("πŸ‘‹ Shutdown success"); - } else { - log.error("😱 Shutdown failed", res.cause()); - } - }); - })); + private static final CountDownLatch shutdownLatch = new CountDownLatch(1); - vertx.deployVerticle(new DataVerticle()) - .compose(id -> vertx.deployVerticle(new HttpVerticle())) - .onSuccess(id -> log.info("πŸš€Start success")) - .onFailure(err -> log.error("😱Start failed", err)); + private static volatile boolean isShuttingDown = false; + + private static final Vertx vertx = Vertx.vertx(); + + private static final DataVerticle dataVerticle = new DataVerticle(); + + private static final HttpVerticle httpVerticle = new HttpVerticle(); + + public static void main(String[] args) { + registerShutdownHooks(); + deployVerticles(); } + private static void registerShutdownHooks() { + Runtime.getRuntime().addShutdownHook(new Thread(() -> { + log.info("πŸ‘‹ Shutdown hook triggered"); + close(); + })); + + try { + sun.misc.Signal.handle(new sun.misc.Signal("TERM"), signal -> { + log.info("πŸ“₯ Received SIGTERM signal"); + close(); + System.exit(0); + }); + + sun.misc.Signal.handle(new sun.misc.Signal("INT"), signal -> { + log.info("πŸ“₯ Received SIGINT signal"); + close(); + System.exit(0); + }); + } catch (IllegalArgumentException e) { + log.warn("⚠️ Signal handling not supported on this platform", e); + } + } + + private static void deployVerticles() { + vertx.deployVerticle(dataVerticle) + .compose(id -> vertx.deployVerticle(httpVerticle)) + .onSuccess(id -> log.info("πŸš€ Start success")) + .onFailure(err -> { + log.error("😱 Start failed", err); + System.exit(1); + }); + } + + private static void close() { + if (isShuttingDown) { + return; + } + vertx.undeploy(httpVerticle.deploymentID()) + .onComplete(res -> { + if (res.succeeded()) { + log.info("πŸ‘‹ Shutdown success"); + } else { + log.error("😱 Shutdown failed", res.cause()); + } + isShuttingDown = true; + shutdownLatch.countDown(); + }); + + try { + shutdownLatch.await(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + } } diff --git a/api/src/main/java/telegram/files/TelegramVerticle.java b/api/src/main/java/telegram/files/TelegramVerticle.java index 22d8c28..2a52cc6 100644 --- a/api/src/main/java/telegram/files/TelegramVerticle.java +++ b/api/src/main/java/telegram/files/TelegramVerticle.java @@ -103,13 +103,20 @@ public class TelegramVerticle extends AbstractVerticle { .onFailure(startPromise::fail); } - public void delete() { - this.execute(new TdApi.Close()) + @Override + public void stop(Promise stopPromise) { + this.close(false) + .onComplete(stopPromise); + } + + public Future close(boolean needDelete) { + return this.execute(new TdApi.Close()) .onSuccess(r -> { log.info("[%s] Telegram account closed".formatted(this.getRootId())); - this.needDelete = true; + this.needDelete = needDelete; }) - .onFailure(e -> log.error("[%s] Failed to close telegram account: %s".formatted(this.getRootId(), e.getMessage()))); + .onFailure(e -> log.error("[%s] Failed to close telegram account: %s".formatted(this.getRootId(), e.getMessage()))) + .mapEmpty(); } public boolean check() { diff --git a/api/src/main/resources/logging.properties b/api/src/main/resources/logging.properties index 1aa9a69..817d72a 100644 --- a/api/src/main/resources/logging.properties +++ b/api/src/main/resources/logging.properties @@ -11,7 +11,7 @@ java.util.logging.ConsoleHandler.level = FINE java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter # \u6587\u4EF6 Handler \u7684\u65E5\u5FD7\u7EA7\u522B -java.util.logging.FileHandler.level = SEVERE +java.util.logging.FileHandler.level = FINE ## \u6587\u4EF6\u65E5\u5FD7\u8DEF\u5F84\u548C\u683C\u5F0F\uFF0C%u \u548C %g \u7528\u4E8E\u751F\u6210\u552F\u4E00\u7684\u65E5\u5FD7\u6587\u4EF6 java.util.logging.FileHandler.pattern = api.log @@ -21,7 +21,7 @@ java.util.logging.FileHandler.append = true # \u662F\u5426\u8FFD\u52A0\u5230\ java.util.logging.FileHandler.formatter = java.util.logging.SimpleFormatter # SimpleFormatter \u7684\u65E5\u5FD7\u683C\u5F0F -java.util.logging.SimpleFormatter.format = [%1$tF %1$tT] [%4$s] %5$s %n%6$s%n +java.util.logging.SimpleFormatter.format = [%1$tF %1$tT] [%4$s] %5$s %6$s%n # ## \u4E3A\u7279\u5B9A\u7684\u65E5\u5FD7\u5668\u8BBE\u7F6E\u65E5\u5FD7\u7EA7\u522B io.netty.level = WARNING diff --git a/docker-compose.yaml b/docker-compose.yaml index dae2656..ed805ad 100644 --- a/docker-compose.yaml +++ b/docker-compose.yaml @@ -10,8 +10,8 @@ services: timeout: 10s start_period: 30s environment: - APP_ENV: ${APP_ENV:-prod} - APP_ROOT: ${APP_ROOT:-/app/data} + APP_ENV: "prod" + APP_ROOT: "/app/data" TELEGRAM_API_ID: ${TELEGRAM_API_ID} TELEGRAM_API_HASH: ${TELEGRAM_API_HASH} ports: