mnemo_cards/mnemo_cards_backend/lib/main.dart
Dmitry 7070be9953
Some checks are pending
Backend CI / test (push) Waiting to run
Backend CI / build (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
getit
2025-12-14 01:10:19 +03:00

142 lines
4.6 KiB
Dart

import 'dart:developer';
import 'dart:io';
import 'package:mnemo_cards_backend/api/mnemo_shelf.dart';
import 'package:mnemo_cards_backend/cron/add_free_packs.dart';
import 'package:mnemo_cards_backend/cron/backup.dart';
import 'package:mnemo_cards_backend/cron/cron_executor.dart';
import 'package:mnemo_cards_backend/cron/generate_promocodes.dart';
import 'package:mnemo_cards_backend/database/database.dart';
import 'package:mnemo_cards_backend/discounts/discounts_manager.dart';
import 'package:mnemo_cards_backend/user/user_manager.dart';
import 'package:mnemo_cards_backend/tests/test_manager.dart';
import 'api/di/injector.dart';
import 'cron/check_admins.dart';
import 'cron/check_payment.dart';
import 'cron/delete_old_archives.dart';
import 'cron/discount_campaign_task.dart';
import 'cron/tasks_seeder.dart';
import 'cron/test_generator.dart';
import 'cron/update_online_users.dart';
import 'packs/free_packs_distributor.dart';
late AppDatabase database;
late final String WORK_DIR;
/// Инициализация подключения к PostgreSQL
Future<AppDatabase> _initDatabase() async {
var attempt = 0;
const maxAttempts = 5;
while (attempt < maxAttempts) {
print('Attempt ${attempt + 1}/$maxAttempts to connect to PostgreSQL...');
try {
// Создать подключение из environment variables
final db = AppDatabase.fromEnvironment();
// Проверить подключение
await db.customSelect('SELECT 1').getSingle();
print('✅ Successfully connected to PostgreSQL');
return database = db;
} catch (e, s) {
print('❌ Error connecting to PostgreSQL: $e');
log('Error connecting to PostgreSQL: $e', error: e, stackTrace: s);
attempt++;
if (attempt < maxAttempts) {
final delay = Duration(seconds: attempt * 5);
print('Retrying in ${delay.inSeconds} seconds...');
await Future.delayed(delay);
}
}
}
throw Exception('Failed to connect to PostgreSQL after $maxAttempts attempts');
}
void main() async {
print('🚀 Starting Mnemo Cards Backend...');
// Читаем environment variables
final backupDir = Platform.environment['BACKUP_DIR'] ?? '../backups/';
WORK_DIR = Platform.environment['WORK_DIR'] ?? '/root/mnemo_cards_backend';
final debugMode = Platform.environment['DEBUG'] == 'true' ||
Platform.environment['DEBUG'] == '1';
print('📂 Working directory: $WORK_DIR');
print('🐛 Debug mode: $debugMode');
print(
'running server in ${(await Process.run('pwd', [], runInShell: true)).stdout}',
);
// For rustore payments
// final rustoreEnabled = false;
// if (rustoreEnabled) {
// final pythonInit = await Process.run(
// workingDirectory: WORK_DIR,
// './prepare_python.sh',
// [],
// runInShell: true,
// );
// print(pythonInit.stdout);
// print(pythonInit.stderr);
// } else {
// log('\n\n*******\nRUSTORE IS DISABLED\n******\n\n', level: 1000);
// }
// Инициализация PostgreSQL
try {
await _initDatabase();
// Настройка зависимостей (AppDatabase уже регистрируется через @singleton в modules.dart)
configureDependencies();
// Запуск API сервера
print('🌐 Starting API server...');
await getIt<MnemoShelf>().initV2();
// Запуск cron jobs
print('⏰ Starting cron jobs...');
// ignore: unawaited_futures
CronManager([
DeleteOldArchives(),
CheckAdminsTask(database),
getIt.get<CheckPaymentTask>(),
AddFreePacks(getIt.get<FreePacksDistributor>(), database),
Backup(backupDir),
GeneratePromocodes(database),
DiscountCampaignTask(getIt.get<DiscountsManager>(), database),
UpdateOnlineUsersTask(getIt.get<UserManager>()),
TasksSeederTask(database),
]).init();
print('✅ Backend started successfully!');
} catch (e, s) {
print('❌ Fatal error starting backend: $e');
log('Fatal error starting backend: $e', error: e, stackTrace: s);
exit(1);
}
// Обработка SIGTERM для graceful shutdown
ProcessSignal.sigterm.watch().listen((signal) async {
print('🛑 Received SIGTERM, shutting down gracefully...');
try {
// Закрыть подключение к БД
await database.close();
print('✅ Database connection closed');
} catch (e, s) {
print('❌ Error closing database: $e');
log('Error closing database: $e', error: e, stackTrace: s);
}
exit(0);
});
}