/// <summary> /// Safe entry point /// </summary> /// <param name="args"></param> private static void Run(string[] args) { try { Log.LogSystem = new LogMultiplier(new FileLog(TraceLevel.Verbose), new ConsoleLog()); string? environmentName = Environment.GetEnvironmentVariable("ASPNETCORE_ENVIRONMENT"); IConfigurationRoot config = new ConfigurationBuilder() .SetBasePath(Directory.GetParent(AppContext.BaseDirectory).FullName) .AddJsonFile("appsettings.json", true, true) .AddJsonFile($"appsettings.{environmentName}.json", true, true) .Build(); string connString = config.GetConnectionString("drdWebDb"); using (PgSqlDbConnect connect = new PgSqlDbConnect(connString)) { connect.Open(); FileHelper.WriteAllBytes(Path.Combine(AppContext.BaseDirectory, "output.sql"), connect.ReadSchema()); } } finally { Log.Dispose(); } }
/// <summary> /// Listen database on selected channels /// </summary> /// <param name="stoppingToken">Cancellation</param> /// <returns></returns> public async Task ListenDb(CancellationToken stoppingToken) { await ParallelHelper.Run(() => { Log.Info($"Listening started for DB: {_dbName}"); while (!stoppingToken.IsCancellationRequested) { try { using (PgSqlDbConnect connect = new PgSqlDbConnect(_connectionString)) { connect.Open(); connect.UnderlyingConnection.Notification += OnNotification; connect.Execute($"LISTEN {PgSqlDbConnect.CHANNEL_GENESIS_REQUEST};"); connect.Execute($"LISTEN {PgSqlDbConnect.CHANNEL_GENESIS_DELETE};"); connect.Execute($"LISTEN {PgSqlDbConnect.CHANNEL_BACKUP_REQUEST};"); while (!stoppingToken.IsCancellationRequested && connect.UnderlyingConnection.State == ConnectionState.Open) { connect.UnderlyingConnection.Wait(100); } } } catch (Exception e) { Log.Error(e); Thread.Sleep(1000); } } }); }
/// <summary> /// Event on DB notification on listened channels occurs /// </summary> /// <param name="sender">Sender of event</param> /// <param name="args">Event arguments</param> private void OnNotification(object sender, NpgsqlNotificationEventArgs args) { try { switch (args.Channel) { case PgSqlDbConnect.CHANNEL_GENESIS_REQUEST: { if (string.IsNullOrEmpty(args.Payload)) { throw new ArgumentException("Payload is empty"); } string filePath = Path.Combine(_config["GenesisOutputDir"], args.Payload + ".sql"); FileHelper.DirectoryEnsure(filePath); string exePath = _config["PgDumpPath"]; string argsText = $"{_config["GenesisArgs"]} --file=\"{filePath}\" {_dbName}"; Log.Info($"RUN {exePath} {argsText}"); Process pgsql = Process.Start(exePath, argsText); pgsql?.WaitForExit(); using (PgSqlDbConnect connect2 = new PgSqlDbConnect(_connectionString)) { connect2.Open(); connect2.Execute($"SELECT pg_notify('{PgSqlDbConnect.CHANNEL_GENESIS_RESPOND}', '{filePath}'::TEXT);"); } break; } case PgSqlDbConnect.CHANNEL_GENESIS_DELETE: { File.Delete(args.Payload); break; } case PgSqlDbConnect.CHANNEL_BACKUP_REQUEST: { string exePath = _config["PgDumpAllPath"]; string filePath = Path.Combine(_config["BackupOutputDir"], _config["BackupFilePrefix"] + DateTimeHelper.Now.ToString(DateTimeHelper.FORMAT_FULL).Replace(".", "_").Replace(":", "_").Replace(" ", "_") + ".pgbak"); string argsText = $"{_config["BackupArgs"]} --file=\"{filePath}\""; Log.Info($"RUN {exePath} {argsText}"); Process pgsql = Process.Start(exePath, argsText); pgsql?.WaitForExit(); break; } } } catch (Exception ex) { Log.Error(ex, $"{args.Channel} [{args.Payload}]"); } }
/// <summary> /// Execution of a service /// </summary> /// <param name="cancellationToken">Cancellation</param> /// <returns></returns> protected override async Task ExecuteAsync(CancellationToken cancellationToken) { Log.Info("PGenesisWorker.Execute!"); await ParallelHelper.Run(() => { string defaultDbName = _config["PgDefaultDb"]; Log.Info($"Default DB name: {defaultDbName}"); string connString = GetConnectionString(defaultDbName); List <string> databases = new List <string>(); using (PgSqlDbConnect connect = new PgSqlDbConnect(connString)) { connect.Open(); using (PgSqlDataReader reader = connect.GetDataReader("SELECT datname FROM pg_database WHERE datistemplate = false AND datname != 'postgres';")) { while (reader.UnderlyingReader.Read()) { databases.Add(reader.ReadString("datname")); } } } List <Task> allTasks = new List <Task>(); foreach (string fDbName in databases) { PGenesisListener fListener = new PGenesisListener(_config, fDbName, GetConnectionString(fDbName)); Task fTask = fListener.ListenDb(cancellationToken); allTasks.Add(fTask); } while (!cancellationToken.IsCancellationRequested) { Task.WaitAll(allTasks.ToArray(), 100); } Log.Info("PGenesisWorker.Execute finished!"); }); }