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
162 lines
5.3 KiB
Dart
162 lines
5.3 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/packs/product_availability_manager.dart';
|
||
import 'package:mnemo_cards_backend/user/user_manager.dart';
|
||
import 'package:mnemo_cards_backend/tests/test_manager.dart';
|
||
import 'package:mnemo_cards_backend/user/user_repository.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';
|
||
import 'storage/minio_service.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();
|
||
|
||
// Инициализация MinIO
|
||
print('📦 Initializing MinIO...');
|
||
try {
|
||
await getIt<MinioService>().ensureBucketsExist();
|
||
print('✅ MinIO initialized successfully');
|
||
} catch (e, s) {
|
||
print('❌ Error initializing MinIO: $e');
|
||
log('Error initializing MinIO: $e', error: e, stackTrace: s);
|
||
// Не прерываем запуск, но логируем ошибку
|
||
}
|
||
|
||
// Запуск API сервера
|
||
print('🌐 Starting API server...');
|
||
await getIt<MnemoShelf>().initV2();
|
||
|
||
// Запуск cron jobs
|
||
print('⏰ Starting cron jobs...');
|
||
// ignore: unawaited_futures
|
||
CronManager([
|
||
DeleteOldArchives(),
|
||
CheckAdminsTask(getIt.get<UserRepository>()),
|
||
getIt.get<CheckPaymentTask>(),
|
||
AddFreePacks(
|
||
getIt.get<FreePacksDistributor>(),
|
||
getIt.get<UserRepository>(),
|
||
getIt.get<ProductAvailabilityManager>(),
|
||
),
|
||
Backup(backupDir),
|
||
GeneratePromocodes(database),
|
||
DiscountCampaignTask(getIt.get<DiscountsManager>(), database),
|
||
UpdateOnlineUsersTask(getIt.get<UserManager>()),
|
||
TasksSeederTask(database),
|
||
TestGeneratorTask(getIt.get<TestManager>(), 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);
|
||
});
|
||
}
|