telegram
Some checks are pending
Backend CI / test (push) Waiting to run
Backend CI / build (push) Blocked by required conditions
Deploy Admin Panel / Deploy Admin Panel (push) Waiting to run
Deploy Admin Panel / Admin Panel Verification (push) Blocked by required conditions
Deploy Mnemo Cards / Deploy Backend (push) Waiting to run
Deploy Mnemo Cards / Deploy Web App (push) Blocked by required conditions
Deploy Mnemo Cards / Final Verification (push) Blocked by required conditions
Deploy Telegram Bot / Deploy Telegram Bot (push) Waiting to run
Some checks are pending
Backend CI / test (push) Waiting to run
Backend CI / build (push) Blocked by required conditions
Deploy Admin Panel / Deploy Admin Panel (push) Waiting to run
Deploy Admin Panel / Admin Panel Verification (push) Blocked by required conditions
Deploy Mnemo Cards / Deploy Backend (push) Waiting to run
Deploy Mnemo Cards / Deploy Web App (push) Blocked by required conditions
Deploy Mnemo Cards / Final Verification (push) Blocked by required conditions
Deploy Telegram Bot / Deploy Telegram Bot (push) Waiting to run
This commit is contained in:
parent
b058dfaaec
commit
7439c6aaa9
2 changed files with 84 additions and 4 deletions
|
|
@ -56,6 +56,9 @@ ENV BACKEND_URL=https://api.mnemo-cards.online \
|
||||||
|
|
||||||
# No EXPOSE needed - bot uses outbound connections only (polling)
|
# No EXPOSE needed - bot uses outbound connections only (polling)
|
||||||
|
|
||||||
|
# Signal for graceful shutdown
|
||||||
|
STOPSIGNAL SIGTERM
|
||||||
|
|
||||||
# Healthcheck - check if process is running
|
# Healthcheck - check if process is running
|
||||||
HEALTHCHECK --interval=30s --timeout=5s --retries=3 --start-period=10s \
|
HEALTHCHECK --interval=30s --timeout=5s --retries=3 --start-period=10s \
|
||||||
CMD pgrep -f "/app/bot" > /dev/null || exit 1
|
CMD pgrep -f "/app/bot" > /dev/null || exit 1
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
import 'package:path/path.dart';
|
import 'package:path/path.dart';
|
||||||
import 'package:mnemo_cards_telegram_bot/bot_config.dart';
|
import 'package:mnemo_cards_telegram_bot/bot_config.dart';
|
||||||
|
|
@ -10,10 +11,65 @@ import 'package:mnemo_cards_telegram_bot/backend_client.dart';
|
||||||
|
|
||||||
const String version = '0.0.1';
|
const String version = '0.0.1';
|
||||||
|
|
||||||
|
// Global variables for graceful shutdown
|
||||||
|
BackendClient? _globalBackendClient;
|
||||||
|
TeleDart? _globalTeledart;
|
||||||
|
bool _isShuttingDown = false;
|
||||||
|
final Completer<void> _shutdownCompleter = Completer<void>();
|
||||||
|
|
||||||
void main() async {
|
void main() async {
|
||||||
|
// Setup signal handlers for graceful shutdown
|
||||||
|
ProcessSignal.sigterm.watch().listen((signal) {
|
||||||
|
print('[BOT] Received SIGTERM, shutting down gracefully...');
|
||||||
|
_shutdown();
|
||||||
|
});
|
||||||
|
|
||||||
|
ProcessSignal.sigint.watch().listen((signal) {
|
||||||
|
print('[BOT] Received SIGINT, shutting down gracefully...');
|
||||||
|
_shutdown();
|
||||||
|
});
|
||||||
|
|
||||||
return _run();
|
return _run();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> _shutdown() async {
|
||||||
|
if (_isShuttingDown) {
|
||||||
|
print('[BOT] Shutdown already in progress');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_isShuttingDown = true;
|
||||||
|
|
||||||
|
print('[BOT] Starting graceful shutdown...');
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (_globalTeledart != null) {
|
||||||
|
print('[BOT] Stopping TeleDart...');
|
||||||
|
// TeleDart doesn't have explicit stop method, but we can dispose resources
|
||||||
|
// The process will exit naturally when main completes
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print('[BOT] Error stopping TeleDart: $e');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (_globalBackendClient != null) {
|
||||||
|
print('[BOT] Disposing BackendClient...');
|
||||||
|
_globalBackendClient!.dispose();
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
print('[BOT] Error disposing BackendClient: $e');
|
||||||
|
}
|
||||||
|
|
||||||
|
print('[BOT] Shutdown complete');
|
||||||
|
|
||||||
|
// Complete the completer to allow main to exit
|
||||||
|
if (!_shutdownCompleter.isCompleted) {
|
||||||
|
_shutdownCompleter.complete();
|
||||||
|
}
|
||||||
|
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
|
||||||
String? _extractCodeFromText(String? rawText) {
|
String? _extractCodeFromText(String? rawText) {
|
||||||
if (rawText == null) {
|
if (rawText == null) {
|
||||||
return null;
|
return null;
|
||||||
|
|
@ -92,6 +148,11 @@ Future<void> _handleCodeClaim({
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _run() async {
|
Future<void> _run() async {
|
||||||
|
if (_isShuttingDown) {
|
||||||
|
print('[BOT] Shutdown in progress, not starting bot');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
print('[BOT] Starting bot version $version');
|
print('[BOT] Starting bot version $version');
|
||||||
BackendClient? backendClient;
|
BackendClient? backendClient;
|
||||||
TeleDart? teledart;
|
TeleDart? teledart;
|
||||||
|
|
@ -110,6 +171,9 @@ Future<void> _run() async {
|
||||||
final username = (await Telegram(config.botToken).getMe()).username;
|
final username = (await Telegram(config.botToken).getMe()).username;
|
||||||
teledart = TeleDart(config.botToken, Event(username!));
|
teledart = TeleDart(config.botToken, Event(username!));
|
||||||
|
|
||||||
|
// Store globally for shutdown handler
|
||||||
|
_globalTeledart = teledart;
|
||||||
|
|
||||||
Future<void> notifyAdmins(String message) async {
|
Future<void> notifyAdmins(String message) async {
|
||||||
for (final admin in adminIds) {
|
for (final admin in adminIds) {
|
||||||
try {
|
try {
|
||||||
|
|
@ -127,6 +191,9 @@ Future<void> _run() async {
|
||||||
apiKey: config.apiKey,
|
apiKey: config.apiKey,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Store globally for shutdown handler
|
||||||
|
_globalBackendClient = backendClient;
|
||||||
|
|
||||||
// At this point all variables are initialized and non-null
|
// At this point all variables are initialized and non-null
|
||||||
final teledartInstance = teledart;
|
final teledartInstance = teledart;
|
||||||
final backendClientInstance = backendClient;
|
final backendClientInstance = backendClient;
|
||||||
|
|
@ -587,7 +654,16 @@ Future<void> _run() async {
|
||||||
|
|
||||||
teledartInstance.start();
|
teledartInstance.start();
|
||||||
print('[BOT] Bot started successfully');
|
print('[BOT] Bot started successfully');
|
||||||
|
|
||||||
|
// Wait for shutdown signal
|
||||||
|
// The bot will run until it receives SIGTERM/SIGINT
|
||||||
|
await _shutdownCompleter.future;
|
||||||
} on Exception catch (e, s) {
|
} on Exception catch (e, s) {
|
||||||
|
if (_isShuttingDown) {
|
||||||
|
print('[BOT] Error during shutdown, exiting...');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
print('[BOT] ERROR: Error: $e\n$s');
|
print('[BOT] ERROR: Error: $e\n$s');
|
||||||
print('[BOT] Error while starting bot: $e');
|
print('[BOT] Error while starting bot: $e');
|
||||||
print('Stack trace: $s');
|
print('Stack trace: $s');
|
||||||
|
|
@ -598,16 +674,17 @@ Future<void> _run() async {
|
||||||
print(' - BACKEND_URL or MNEMO_BACKEND_URL (optional, default: https://api.mnemo-cards.online)');
|
print(' - BACKEND_URL or MNEMO_BACKEND_URL (optional, default: https://api.mnemo-cards.online)');
|
||||||
print(' - BOT_SHARE_DAILY_LIMIT (optional, default: 1)');
|
print(' - BOT_SHARE_DAILY_LIMIT (optional, default: 1)');
|
||||||
|
|
||||||
// Cleanup resources before restart
|
// Cleanup resources
|
||||||
try {
|
try {
|
||||||
backendClient?.dispose();
|
backendClient?.dispose();
|
||||||
} catch (_) {
|
} catch (_) {
|
||||||
// Ignore cleanup errors
|
// Ignore cleanup errors
|
||||||
}
|
}
|
||||||
|
|
||||||
print('Restarting in 5 seconds...');
|
// Exit with error code instead of restarting
|
||||||
await Future.delayed(const Duration(seconds: 5));
|
// Let Docker/Coolify handle restarts with restart policy
|
||||||
return _run();
|
print('[BOT] Exiting with error code...');
|
||||||
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue