# 백그라운드 작업과 워커

Background jobs and workers

#### 설명

Axs 프레임워크에서는 응용 프로그램의 백그라운드 스레드에서 작업을 실행하는 데 사용되는 백그라운드 작업(Job) 및 워커(Worker)를 제공합니다

#### 1. 백그라운드 작업

백그라운드 작업은 대기열 및 지속적 방식으로 백그라운드에서 실행할 일부 작업을 사용자의 상호작용을 통해 대기열에 추가하는 데 사용됩니다. 여러 가지 이유로 백그라운드 작업이 필요할 수 있습니다.

사용자가 기다리지 않고 오래 실행되는 작업을 수행하려는 경우. 예를 들어 사용자가 '통계' 버튼을 눌러 오래 실행되는 통계 작업을 시작한다고 가정해 보겠습니다. 이 작업을 대기열에 추가하고 통계 보고서가 완료되면 사용자에게 이메일을 통해 보고서 결과를 보냅니다.

![Alt text](/files/mTWhAkB4sZfhEcls7Zp8)

아래 샘플 코드로 사용할 수 있습니다.

**1. 백그라운드 작업 생성**

```csharp
public class SimpleMailJob : AsyncBackgroundJob<SimpleMailJobArgs>, ITransient
{
    private readonly IEmailSender _emailSender;

    public SimpleMailJob(IEmailSender emailSender) 
    {
        _emailSender = emailSender;
    }

    [UnitOfWork]
    public override async Task ExecuteAsync(SimpleMailJobArgs args)
    {
        // ...
        
        await _emailSender.SendAsync(args.To, args.Subject, args.Body);
    }
}
```

**2. 작업 인수 정의**

```csharp
[Serializable]
public class SimpleMailJobArgs
{
    public string To { get; set; }

    public string Subject { get; set; }

    public string Body { get; set; }
}
```

인수를 단순하게 유지하고 **\[Serializable]** 속성을 정의하는것이 좋습니다.

**3. 큐에 새 작업 추가**

* StatisticsAppController 에서 아래와 같은 코드로 작업 대기열에 추가할 수 있다.

```csharp
[AxsAuthorize]
public class StatisticsAppController : AppController
{
    private readonly IBackgroundJobManager _backgroundJobManager;

    public StatisticsAppController(IBackgroundJobManager backgroundJobManager)
    {
        _backgroundJobManager = backgroundJobManager;
    }

    public async Task AggregationAsync(EmailInput input)
    {
        // ...
        
        var args = new SimpleMailJobArgs {
            To = AxsSession.EmailAddress,            
            Subject = input.Subject,
            Body = input.Body
        };
        await _backgroundJobManager.EnqueueAsync<SimpleMailJob, SimpleMailJobArgs>(args);
    }
}
```

`StatisticsAppController`에서 `EnqueueAsync`를 호출하여 실행되는 것을 확인할 수 있습니다.\
이때 `StatisticsAppController`의 결과 값은 대기열의 실행 여부와 상관없이 동작합니다.

`EnqueueAsync` 메서드에는 우선순위 및 지연과 같은 매개변수를 사용할 수 있습니다.

```csharp
public BackgroundJobManager : IBackgroundJobManager
{
    public async Task<string> EnqueueAsync<TJob, TArgs>(TArgs args, BackgroundJobPriority priority = BackgroundJobPriority.Normal, TimeSpan? delay = null)
    {
        // ...
    }
}                   
```

#### 2. 백그라운드 워커

백그라운드 워커는 사용자와의 상호 작용없이 단독으로 돌아가는 작업입니다. 일반적으로 주기적 실행되는 반복 작업을 수행합니다.

* 주기적으로 실행하여 오래된 로그 파일를 삭제할 수 있습니다.
* 주기적으로 실행하여 잠김 처리된 사용자를 식별하고 관리자에게 알림을 보내 처리할 수 있습니다.
* 타 시스템과의 연동을 위해 특정 시간에 데이터를 가져오거나, 내보내는 작업을 진행할 수 있습니다.

![Alt text](/files/UgGzlh6S7A0bkVav49FD)

아래 샘플 코드로 사용할 수 있습니다.

```csharp
public class SampleBackgroundWorker : PeriodicBackgroundWorkerBase, ITransient
{
    /// <summary>
    /// <see cref="SampleBackgroundWorker"/> 클래스의 새 인스턴스를 초기화합니다.
    /// </summary>
    /// <param name="timer">A timer.</param>
    public SampleBackgroundWorker(AxsTimer timer) : base(timer)
    {
        // 1초 후에 DoWork가 시작 되도록 세팅
        Timer.Period = 1000 * 1;
    }

    /// <summary>
    /// 이 메서드를 구현하여 주기적인 작업을 수행해야 합니다.
    /// </summary>
    [UnitOfWork]
    protected override void DoWork()
    {
        // 모든 테넌트 데이터에 접근이 되도록 필터를 해제 한다.
        using (CurrentUnitOfWork.DisableFilter(AxsDataFilters.MayHaveTenant)) {
            // DB 작업 또는 배치 작업 진행
            if (IsRunning) {
                // Worker 중지 요청을 받지 안았다면 실행
                // 업무 로직을 실행 하도록 한다.

                Logger.Info("SampleBackgroundWorker 실행 됨");
            }
        }
        // 일정 시간이 되었을 때 외부 연동 작업 진행
        Timer.Period = 1000 * 1;
    }
}
```

위 워커가 동작하기 위해서는 아래 코드와 같이 모듈에서 등록을 해줘야 합니다.

```csharp
public override void PostInitialize()
{
    // Worker를 등록해서 동작하도록 한다.
    var workManager = IocManager.Resolve<IBackgroundWorkerManager>();
    workManager.Add(IocManager.Resolve<SampleBackgroundWorker>());
}
```


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.axuslab.com/5.-background-services/background_jobs_and_workers.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
