Console์—์„œ IHost ์‚ฌ์šฉ

๋งŒ๋“ค๊ณ ์žํ•˜๋Š” ๊ฒƒ์€ .NET 5 Console Application์—์„œ Azure Service Bus์˜ Queue๋ฐ์ดํ„ฐ๋ฅผ 1์ดˆ ๊ฐ„๊ฒฉ์œผ๋กœ POPํ•˜๋Š” ๊ฒƒ์ž…๋‹ˆ๋‹ค.

๊ตฌ๊ธ€๋งํ•ด์„œ IHost๋ฅผ ํ†ตํ•ด ์„ค์ •ํŒŒ์ผ์„ ๊ฐ€์ ธ์˜ค๋Š” ๊ฒƒ๊นŒ์ง€๋Š” ์„ฑ๊ณตํ–ˆ์Šต๋‹ˆ๋‹ค.
ํ•˜์ง€๋งŒ ์„œ๋น„์Šค๋ฅผ Singleton์œผ๋กœ ๋“ฑ๋กํ–ˆ๋”๋‹ˆ Service๋ฅผ ํ˜ธ์ถœํ•˜๊ธฐ ์ „๊นŒ์ง€๋Š” ์ƒ์„ฑ์ž๊ฐ€ ํ˜ธ์ถœ๋˜๋Š” ๊ฒƒ๋„ ๋ณผ ์ˆ˜ ์—†์—ˆ๊ณ , ๊ทธ๋ ‡๋‹ค๊ณ  Main ํ•จ์ˆ˜์— RunAsync๋ฅผ ํ•˜๊ธฐ์ „์— while ๋ฌดํ•œ๋ฃจํ”„๋ฅผ ๋Œ๋ฆฌ์ž๋‹ˆ ์ด๊ฑด ์•„๋‹Œ๊ฑฐ ๊ฐ™์Šต๋‹ˆ๋‹ค. ์–ด๋–ป๊ฒŒ ๊ตฌํ˜„ ํ•  ์ˆ˜ ์žˆ์„๊นŒ์š”?

    class Program
    {
        static async Task Main(string[] args)
        {
            using IHost host = CreateHostBuilder(args).UseConsoleLifetime().Build();
            await host.RunAsync();
        }

        static IHostBuilder CreateHostBuilder(string[] args)
        {
            IHostBuilder rtnValue = Host.CreateDefaultBuilder(args)
                .ConfigureAppConfiguration((hostingContext, configuration) =>
                {
                    configuration.Sources.Clear();

                    IHostEnvironment env = hostingContext.HostingEnvironment;

                    configuration.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
                    configuration.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
                    //configuration.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);

                    IConfigurationRoot configurationRoot = configuration.Build();
                    AzureServiceBusSettings settings = new();
                    configurationRoot.GetSection(nameof(AzureServiceBusSettings)).Bind(settings);

                    Console.WriteLine($"AzureServiceBus Key={settings.Endpoint}");
                    Console.WriteLine($"AzureSerivceBus QueueName={settings.QueueName}");
                })
                .ConfigureServices((context, services) =>
                {
                    services.Configure<AzureServiceBusSettings>(context.Configuration);
                    services.AddSingleton<AzureServiceBusService>();
                });

            return rtnValue;
        }
    }
        //
        // ์š”์•ฝ:
        //     Adds a singleton service of the type specified in serviceType with an instance
        //     specified in implementationInstance to the specified Microsoft.Extensions.DependencyInjection.IServiceCollection.
        //
        // ๋งค๊ฐœ ๋ณ€์ˆ˜:
        //   services:
        //     The Microsoft.Extensions.DependencyInjection.IServiceCollection to add the service
        //     to.
        //
        //   serviceType:
        //     The type of the service to register.
        //
        //   implementationInstance:
        //     The instance of the service.
        //
        // ๋ฐ˜ํ™˜ ๊ฐ’:
        //     A reference to this instance after the operation has completed.
        public static IServiceCollection AddSingleton(this IServiceCollection services, Type serviceType, object implementationInstance);

์ด ๋ฉ”์†Œ๋“œ๋ฅผ ์จ๋ณด์„ธ์š”

AzureServiceBusService ๋ผ๋Š” ํด๋ž˜์Šค๊ฐ€

    public AzureServiceBusService(
            ILogger<AzureServiceBusService> logger,
            IHostApplicationLifetime appLifetime,
            IOptions<AzureServiceBusSettings> settings)
        {
            _logger = logger;
            _appLifetime = appLifetime;
            connString = settings.Value.Endpoint;
            queueName = settings.Value.QueueName;
            timerState = new TimerState { Counter = TimerStateEnum.Run };
            popTimer = new Timer(
                callback: new TimerCallback(PopData),
                state: timerState,
                dueTime: 0,
                period: 1000);
        }

์œ„์™€ ๊ฐ™์€ ์ƒ์„ฑ์ž๋ฅผ ์ง€๋‹ˆ๊ณ  ์žˆ์Šต๋‹ˆ๋‹คโ€ฆ ๊ธฐ๋ณธ ์ƒ์„ฑ์ž๋ฅผ ๋งŒ๋“ค์ž๋‹ˆ, ํŒŒ๋ผ๋ฏธํ„ฐ๋ฅผ ์„œ๋น„์Šค ๋“ฑ๋ก ์‹œ ๋ฐ›์ง€ ๋ชปํ•˜๋Š” ์ ์ด ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋ ‡๊ฒŒํ•˜๋ฉด static์œผ๋กœ settings๊ฐ’๋“ค์„ ๋ฐ›์•„์„œ ๋„˜๊ฒจ์ค˜์•ผํ• ๊ฑฐ๊ฐ™์€๋ฐ, ๊ทธ๋ ‡๊ฒŒ ํ•˜๋Š” ๋ฐฉ๋ฒ• ๋ฐ–์— ์—†์„๊นŒ์š”โ€ฆ?

์•„โ€ฆ ์ธ์Šคํ„ด์Šค๋ฅผ ๋„˜๊ฒจ์ฃผ๋Š” ๋ฐฉ์‹์ž…๋‹ˆ๋‹ค. ์›ํ•˜๋Š” ๊ฐœ์ฒด๋ฅผ ์ƒ์„ฑํ›„ ์ธ์ž๋กœ ๋„˜๊ฒจ์ฃผ๋ฉด ๋˜์–ด์š”

์ €๋„ ์ฃผ๋ง์— ํฌ๋ก ์ž‘์—…์ด ํ•„์š”ํ•ด Quartz.net ์ด๋‚˜ Hangfire ์•Œ์•„๋ณด๋‹ค ๊ฐ€๋ฒผ์šด ์„œ๋น„์Šค๊ฐ€ ํ•„์š”ํ•ด์„œ Hangfire Cronos๋ณด๊ณ  ๊ฐ„๋‹จํžˆ ์“ฐ๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ํ•„์š”ํ•˜์‹ ๊ฒŒ ๋งž๋Š”๊ฑด์ง€๋Š” ๋ชจ๋ฅด๊ฒ ๋„ค์š”.

IHostedService๋ฅผ ํ†ตํ•ด ์„œ๋น„์Šค๋ฅผ singleton์œผ๋กœ ์ƒ์„ฑํ•˜๊ณ  Cron Expression์„ ์ด์šฉํ•ด ํƒ€์ด๋จธ๋ฅผ ์กฐ์ž‘ํ•ฉ๋‹ˆ๋‹ค.
์ผ๋ถ€ ์ˆ˜์ •ํ•ด์„œ ์‚ฌ์šฉํ•ด๋ณด๋‹ˆ ์ž˜ ์ž‘๋™ํ•ฉ๋‹ˆ๋‹ค.

2๊ฐœ์˜ ์ข‹์•„์š”

์•„โ€ฆQuartz.NET ์ด ๋ญ”์ง€ ๋ชจ๋ฅด๊ฒ ๋Š”๋ฐ ๋‚˜์ค‘์— ์ฐพ์•„๋ด์•ผ๊ฒ ๊ตฐ์š”.
IHostedService์—์„œ ํžŒํŠธ๋ฅผ ์–ป์–ด์„œ ๋‹ค์Œ๊ณผ ๊ฐ™์ด ์ž‘์„ฑํ–ˆ๋”๋‹ˆ ์›ํ•˜๋Š” ๋Œ€๋กœ ๋™์ž‘ํ•ฉ๋‹ˆ๋‹ค!!
๊ฐ์‚ฌํ•ฉ๋‹ˆ๋‹ค.

    class Program
    {
        static async Task Main(string[] args)
        {
            using IHost host = CreateHostBuilder(args).Build();
            await host.RunAsync();
        }

        static IHostBuilder CreateHostBuilder(string[] args)
        {
            IHostBuilder rtnValue = Host.CreateDefaultBuilder(args)
                .UseConsoleLifetime()
                .ConfigureAppConfiguration((hostingContext, configuration) =>
                {
                    configuration.Sources.Clear();

                    IHostEnvironment env = hostingContext.HostingEnvironment;

                    configuration.SetBasePath(hostingContext.HostingEnvironment.ContentRootPath);
                    configuration.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true);
                    //configuration.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true, reloadOnChange: true);

                    IConfigurationRoot configurationRoot = configuration.Build();
                    AzureServiceBusSettings settings = new();
                    configurationRoot.GetSection(nameof(AzureServiceBusSettings)).Bind(settings);

                    Console.WriteLine($"AzureServiceBus Key={settings.Endpoint}");
                    Console.WriteLine($"AzureSerivceBus QueueName={settings.QueueName}");
                })
                .ConfigureServices((context, services) =>
                {
                    services.Configure<AzureServiceBusSettings>(context.Configuration.GetSection(AzureServiceBusSettings.Settings)); // ์—ฌ๊ธฐ ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค.
                    services.AddHostedService<AzureServiceBusService>(); // ์—ฌ๊ธฐ ์ˆ˜์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. Singleton -> AddHostedService
                });

            return rtnValue;
        }
    }
2๊ฐœ์˜ ์ข‹์•„์š”