Example #1
0
        /// <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!");
            });
        }