λ°˜μ‘ν˜•

개발 배경

μ €λŠ” νšŒμ‚¬μ—μ„œ 업무 관리λ₯Ό μœ„ν•΄ μ‹œλ†€λ‘œμ§€ λ„μ»€μ—μ„œ λ ˆλ“œλ§ˆμΈμ„ μ‚¬μš©ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. 그리고 λ ˆλ“œλ§ˆμΈμ˜ 메일 섀정을 톡해 일감 생성, νŽΈμ§‘ μ‹œ λ©”μΌλ‘œ μ•Œλ¦Όμ„ λ°›κ³  μžˆμŠ΅λ‹ˆλ‹€. λ©”μΌμ˜ 경우 μ•„μ›ƒλ£©μœΌλ‘œ ν™•μΈν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. 그런데 μ§€κΈˆκΉŒμ§€ λ ˆλ“œλ§ˆμΈμ„ μ‚¬μš©ν•˜λ©΄μ„œ λ„ˆλ¬΄λ‚˜ μ•„μ‰¬μš΄ 점이 μžˆμ—ˆμŠ΅λ‹ˆλ‹€. λ°”λ‘œ μ•Œλ¦Όμ„ μ¦‰μ‹œ 확인할 수 μ—†λ‹€λŠ” 것이죠

λ ˆλ“œλ§ˆμΈ μ•Œλ¦Όμ΄ μžˆλŠ”μ§€ ν™•μΈν•˜κΈ° μœ„ν•΄ μ•„μ›ƒλ£©μ—μ„œ 직접 보내기/λ°›κΈ° λ²„νŠΌμ„ ν΄λ¦­ν•˜κ±°λ‚˜ μ‹œκ°„ 간격을 짧게 μ„€μ •ν•΄μ•Ό ν–ˆμŠ΅λ‹ˆλ‹€. ν•˜μ§€λ§Œ PCμ—μ„œλŠ” μ΄λ ‡κ²Œ ν™•μΈν•˜λ©΄ λ˜μ§€λ§Œ μŠ€λ§ˆνŠΈν°μ—μ„œλŠ” μ•Œλ¦Ό λ°›κΈ°κ°€ 쉽지 μ•ŠμŠ΅λ‹ˆλ‹€. μ•Œλ¦Όμ„ μΌœμžλ‹ˆ μˆ˜μ‹ λ˜λŠ” λͺ¨λ“  메일에 λŒ€ν•΄ μ•Œλ¦Όμ΄ μ˜€λ‹ˆ 영 λΆˆνŽΈν–ˆμŠ΅λ‹ˆλ‹€

κ·Έλž˜μ„œ μƒκ°ν•œ 것이, 'λ ˆλ“œλ§ˆμΈ 일감이 μƒμ„±λ˜λ©΄ λ©”μ‹ μ €λ‘œ μ•Œλ¦Όμ„ 쀄 수 μžˆμ§€ μ•Šμ„κΉŒ'μž…λ‹ˆλ‹€. κ²Œλ‹€κ°€ μ €λŠ” 사내 λ©”μ‹ μ €λ‘œ μ‹œλ†€λ‘œμ§€ μ±—(Chat)을 μ‚¬μš©ν•˜κ³  있기 λ•Œλ¬Έμ—, μ±—μœΌλ‘œ μ•Œλ¦Ό λ©”μ‹œμ§€λ₯Ό λ°›κΈΈ μ›ν–ˆμŠ΅λ‹ˆλ‹€

그런데 μ—­μ‹œλ‚˜ μ•ˆ λ˜λŠ” 건 μ—†λ”κ΅°μš”. λ ˆλ“œλ§ˆμΈμ€ REST APIλ₯Ό, 챗은 Incoming Webhook을 μ œκ³΅ν•˜κ³  μžˆμ—ˆμŠ΅λ‹ˆλ‹€. 즉, μ‹€μ‹œκ°„μœΌλ‘œ λ ˆλ“œλ§ˆμΈ REST APIλ₯Ό ν˜ΈμΆœν•˜μ—¬ μ‹ κ·œ 일감을 μ‘°νšŒν•˜κ³ , 일감이 μžˆλ‹€λ©΄ μ±—μœΌλ‘œ λ©”μ‹œμ§€λ₯Ό 보내면 λ˜λŠ” 것이죠!

ꡬ상도

ASP.NET Core Worker Service

그런데 λ¬Έμ œκ°€ μžˆμ—ˆμŠ΅λ‹ˆλ‹€. 'μ–΄λ””'μ—μ„œ ν”„λ‘œκ·Έλž¨μ„ λŒλ¦¬λŠλƒμž…λ‹ˆλ‹€. μ²˜μŒμ—λŠ” νŠΉμ • 컴퓨터에 ν”„λ‘œκ·Έλž¨μ„ μ‹€ν–‰ν•΄ λ¬΄ν•œ λ£¨ν”„λ‘œ 계속 λŒλ¦΄μ§€, μ•„λ‹ˆλ©΄ μœˆλ„μš° μ„œλΉ„μŠ€λ‘œ κ°œλ°œν•˜μ—¬ 컴퓨터가 μΌœμ§€λ©΄ 계속 λŒμ•„κ°€κ²Œ 할지 고민을 ν–ˆμ—ˆμŠ΅λ‹ˆλ‹€. 그런데 μƒκ°ν•΄λ³΄λ‹ˆ μ €λŠ” μ‹œλ†€λ‘œμ§€ μ„œλ²„λ₯Ό μ‚¬μš©ν•˜κ³  μžˆμ—ˆμŠ΅λ‹ˆλ‹€. 즉, μ„œλ²„μ— κ°œλ°œν•œ ν”„λ‘œκ·Έλž¨μ„ 돌리면 λ˜μ§€ μ•Šμ„κΉŒ μ‹Άμ—ˆμ£ . κ·Έλž˜μ„œ μ•Œκ²Œ 된 것이 ASP.NET Coreμ˜€μŠ΅λ‹ˆλ‹€.

ASP.NET CoreλŠ” Windows, macOS 및 Linuxμ—μ„œ 인터넷 μ—°κ²° 앱을 λ™μž‘ν•  수 μžˆλŠ” ν”„λ ˆμž„ μ›Œν¬μž…λ‹ˆλ‹€. 그리고 C#을 μ§€μ›ν•©λ‹ˆλ‹€. 즉, κ°„λ‹¨νžˆ μ„€λͺ…ν•˜λ©΄ μ œκ°€ μ›ν•˜λŠ” λ™μž‘μ„ μˆ˜ν–‰ν•˜λŠ” μ½”λ“œλ₯Ό λΉŒλ“œν•˜κ³  κ·Έ 결과물을 ASP.NET Coreλ₯Ό 톡해 μ„œλΉ„μŠ€λ₯Ό λ™μž‘ν•  수 μžˆλ‹€λŠ” κ²ƒμž…λ‹ˆλ‹€.

κ²Œλ‹€κ°€ Visual Studioμ—μ„œ μ œμž‘ κ°€λŠ₯ν•œ ASP.NET Core Worker Service(μž‘μ—…μž μ„œλΉ„μŠ€) ν…œν”Œλ¦Ώμ€ μž₯κΈ°κ°„ μ‹€ν–‰λ˜λŠ” μ„œλΉ„μŠ€ 앱을 κ°œλ°œν•˜κΈ° μœ„ν•΄ μ œκ³΅λ©λ‹ˆλ‹€. 즉, 이번 ꡬ상과 같이 λ©ˆμΆ”μ§€ μ•Šκ³  κ³„μ†ν•΄μ„œ 돌릴 μ„œλΉ„μŠ€λ₯Ό μ œμž‘ν•˜κΈ° μœ„ν•œ ν”„λ‘œμ νŠΈλΌλŠ” 것이죠.

개발 μˆœμ„œ

이제 본격적으둜 κ°œλ°œμ— λŒμž…ν•˜κΈ°μ— μ•žμ„œ, 'μ–΄λ–»κ²Œ' κ°œλ°œν•΄ λ‚˜κ°ˆ 것인지 μ„€λͺ…ν•˜κ² μŠ΅λ‹ˆλ‹€. 쀑간 쀑간 λ‚΄μš©μ΄ κ½€ λ§Žμ•„μ„œ ν•˜μœ„ ν¬μŠ€νŒ…μ„ μ²¨λΆ€ν–ˆμŠ΅λ‹ˆλ‹€.

1. ν…ŒμŠ€νŠΈ ν”„λ‘œκ·Έλž¨

μš°μ„  λ ˆλ“œλ§ˆμΈ REST API와 μ‹œλ†€λ‘œμ§€ μ±— Incoming Webhook을 연동할 쀄 μ•Œμ•„μ•Όκ² μ£ ? λ ˆλ“œλ§ˆμΈ REST API와 Incoming Webhook을 λ‹€λ£¨λŠ” 방법은 μ•„λž˜ 링크λ₯Ό μ°Έκ³ ν•˜μ„Έμš”. 

[.Net] C# λ ˆλ“œλ§ˆμΈ REST API μ‚¬μš©ν•˜λŠ” 방법(예제 포함)

[챗봇/.NET] C#μ—μ„œ μ‹œλ†€λ‘œμ§€ Chat에 챗봇 λ©”μ‹œμ§€ 보내기(예제 포함)

2. Windows Docker with Worker Service

λ„μ»€λŠ” Windows와 Linux 운영체제 λͺ¨λ‘ μ§€μ›ν•˜λŠ”λ°μš”. μ΅œμ’… λͺ©ν‘œλŠ” λ¦¬λˆ…μŠ€ 기반의 μ‹œλ†€λ‘œμ§€ λ„μ»€μ΄μ§€λ§Œ, 쀑간 검증을 μœ„ν•΄ μœˆλ„μš°μš© λ„μ»€μ—μ„œ λ¨Όμ € ν…ŒμŠ€νŠΈλ₯Ό μ§„ν–‰ν•˜λ €κ³  ν•©λ‹ˆλ‹€. 그리고 λ„μ»€μ—μ„œ μ„œλΉ„μŠ€λ₯Ό κ΅¬λ™ν•˜κΈ° μœ„ν•΄μ„œλŠ” Visual Studioμ—μ„œ μ œκ³΅ν•˜λŠ” μž‘μ—…μž μ„œλΉ„μŠ€(Worker Service) ν…œν”Œλ¦Ώμ„ μ‚¬μš©ν•˜λ©΄ λ©λ‹ˆλ‹€.

이와 κ΄€λ ¨λœ λ‚΄μš©μ€ μ•„λž˜ 링크λ₯Ό μ°Έκ³ ν•˜μ„Έμš”.

[ASP.NET] C# Windows Docker 용 μž‘μ—…μž μ„œλΉ„μŠ€ λ§Œλ“œλŠ” 방법

3. Synology Docker with Worker Service

μœˆλ„μš° λ„μ»€μ—μ„œ 검증이 됐닀면, μ‹œλ†€λ‘œμ§€ 도컀에 이미지λ₯Ό 올리고 μ»¨ν…Œμ΄λ„ˆλ₯Ό μ‹€ν–‰ν•˜λ©΄ λμž…λ‹ˆλ‹€. μ—¬κΈ°μ„œ Puttyλ₯Ό μ‚¬μš©ν•˜μ—¬ μ‹œλ†€λ‘œμ§€μ— μ ‘μ†ν•˜λŠ” 과정이 있기 λ•Œλ¬Έμ— PuTTY μ‚¬μš© 방법도 μˆ™μ§€ν•˜μ‹œκΈ° λ°”λžλ‹ˆλ‹€.

[Synology NAS] ν‘Έν‹°(PuTTY)둜 μ‹œλ†€λ‘œμ§€ μ ‘μ†ν•˜λŠ” 방법

PuTTY μ‚¬μš©λ²•λ„ μ΅ν˜”λ‹€λ©΄ λ¦¬λˆ…μŠ€ λ„μ»€μš© μž‘μ—…μž μ„œλΉ„μŠ€ λ§Œλ“œλŠ” 방법을 μ°Έκ³ ν•˜μ„Έμš”.

[ASP.NET] C# μ‹œλ†€λ‘œμ§€ Linux Docker 용 μž‘μ—…μž μ„œλΉ„μŠ€ λ§Œλ“œλŠ” 방법​

λ™μž‘ 섀계

ν˜„μž¬ μ œκ°€ μ‚¬μš©ν•˜λŠ” λ ˆλ“œλ§ˆμΈμ—λŠ” 타 λΆ€μ„œμ—μ„œ 업무λ₯Ό μš”μ²­ν•  수 μžˆλŠ” '업무 μš”μ²­' ν”„λ‘œμ νŠΈκ°€ λ”°λ‘œ μžˆμŠ΅λ‹ˆλ‹€. 타 λΆ€μ„œ λ‹΄λ‹Ήμžλ“€μ€ λͺ¨λ‘ μ΄κ³³μ—μ„œ 일감을 μƒμ„±ν•˜μ—¬ 업무λ₯Ό μš”μ²­ν•˜κ²Œ λ©λ‹ˆλ‹€. 그리고 처리된 일감은 ν•΄λ‹Ή ν”„λ‘œμ νŠΈμ—μ„œ μ‚¬λΌμ§€κ²Œ λ©λ‹ˆλ‹€.

이λ₯Ό 기반으둜, μ œκ°€ μƒκ°ν•œ μ„œλΉ„μŠ€μ˜ λ™μž‘μ€ λ‹€μŒκ³Ό κ°™μŠ΅λ‹ˆλ‹€.
β‘  업무 μš”μ²­ ν”„λ‘œμ νŠΈμ— μ‘΄μž¬ν•˜λŠ” 'μ²˜λ¦¬λ˜μ§€ μ•Šμ€ 일감'을 μ‘°νšŒν•œλ‹€.
β‘‘ 일감 번호λ₯Ό κΈ°μ–΅ν•˜μ—¬ μ€‘λ³΅μœΌλ‘œ λ©”μ‹œμ§€λ₯Ό μ „λ‹¬ν•˜μ§€ μ•Šλ„λ‘ ν•œλ‹€.
β‘’ λ©”μ‹ μ €λ‘œ 일감 μ›Ή μ‚¬μ΄νŠΈ μ£Όμ†Œμ™€ 제λͺ©μ„ λ©”μ‹œμ§€λ‘œ μ „μ†‘ν•œλ‹€. 

μ•„μ£Ό κ°„λ‹¨ν•˜μ£ ? 이λ₯Ό 기반으둜 μ½”λ“œ κ΅¬ν˜„μ„ ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

μ„œλΉ„μŠ€ λ™μž‘

μ½”λ“œ κ΅¬ν˜„

쀑간쀑간 확인해야 ν•  것듀이 κ½€ λ§Žμ•˜μŠ΅λ‹ˆλ‹€. 그럼 본격적으둜 ν”„λ‘œμ νŠΈμ˜ λͺ©ν‘œλ₯Ό μœ„ν•œ 핡심 μ½”λ“œ κ΅¬ν˜„μ€ μ–΄λ–»κ²Œ λ˜λŠ”μ§€ μ‚΄νŽ΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

public class Worker : BackgroundService
{
	//μ‹ κ·œ 일감 μ•Œλ¦Ό λ©”μ‹œμ§€ 쀑볡 방지λ₯Ό μœ„ν•œ 객체
	private Dictionary<int, string> _list = new Dictionary<int, string>();
	
    //... μƒλž΅...
    
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        while (!stoppingToken.IsCancellationRequested)
        {
            try
            {
            	//1초 λ§ˆλ‹€ 지연
                await Task.Delay(1000, stoppingToken);
				//ν˜„μž¬ μ‘΄μž¬ν•˜λŠ” 일감 쑰회
                var issues = searchIssues();
                //μ‘΄μž¬ν•˜λŠ” 일감이 μžˆλ‹€λ©΄
                if (issues != null)
                {
                    foreach (var issue in issues)
                    {
                        try
                        {
                        	//일감 λ²ˆν˜Έμ™€ 제λͺ©μ„ _list에 μΆ”κ°€
                            _list.Add(issue.Id, issue.Subject);
                            //μ‹œλ†€λ‘œμ§€ Chat에 λ©”μ‹œμ§€ 전솑
                            notifyChatMessage(issue);
                        }
                        catch (Exception exc)
                        {
                        	//이미 _list에 일감 제λͺ©μ΄ μ‘΄μž¬ν•˜λ©΄ μ˜ˆμ™Έλ‘œ 처리
                            continue;
                        }
                    }
                }
				//ν˜„μž¬ μ‘΄μž¬ν•˜λŠ” 일감이 μ—†λ‹€λ©΄
                else 
                {
                	//λͺ¨λ“  μ‹ κ·œ 일감을 Chat에 λ©”μ‹œμ§€λ₯Ό λ³΄λƒˆμœΌλ―€λ‘œ,
                    //ν˜„μž¬ μ‘΄μž¬ν•˜λŠ” λͺ©λ‘μ„ μ§€μš΄λ‹€(쀑볡 방지)
                    if (_list.Count != 0)
                    {
                        _list.Clear();
                    }
                }
            }
            catch(Exception exc)
            {
                _logger.LogInformation(exc.Message);
            }
        }
    }
}

μ½”λ“œλŠ” 생각보닀 μ•„μ£Ό κ°„λ‹¨ν•˜κ³ , μ£Όμ„μœΌλ‘œλ„ μΆ©λΆ„νžˆ μ„€λͺ…이 될 것 κ°™μŠ΅λ‹ˆλ‹€. 쀑간에 ν˜ΈμΆœν•˜λŠ” searchIssues()λŠ” λ ˆλ“œλ§ˆμΈ REST API ν¬μŠ€νŒ…μ„, notifyChatMessage()λŠ” Chat에 챗봇 λ©”μ‹œμ§€ 보내기 ν¬μŠ€νŒ…μ„ μ°Έκ³ ν•˜μ„Έμš”.

ν›„κΈ°

μ‹€μ œ μ•Œλ¦Ό ν™”λ©΄

ν•΄λ‹Ή μ„œλΉ„μŠ€λ₯Ό μ œμž‘ν•œ ν›„ λΉ λ₯΄κ²Œ 업무 μš”μ²­ 일감을 κ΄€λ¦¬ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. μ΄μ „μ—λŠ” λ‹€λ₯Έ 일을 ν•˜λŠλΌ λ°”μ˜λ©΄ 메일 확인이 λŠ¦μ–΄ 업무 확인이 λŠ¦μ–΄μ‘ŒλŠ”λ°, ν˜„μž¬λŠ” PC λ˜λŠ” 슀마트폰으둜 μ•Œλ¦Όμ΄ μ¦‰μ‹œ μ˜€λ‹ˆ λ°”μ˜λ”λΌλ„ 빨리 ν™•μΈν•˜κ²Œ λ˜μ–΄ 업무 지연이 μ΅œμ†Œν™”λ˜μ—ˆμŠ΅λ‹ˆλ‹€. μ—­μ‹œ λΆˆνŽΈν•˜λ©΄ 직접 λ§Œλ“€μ–΄μ„œ ν•΄κ²°ν•˜λŠ” 것이 정닡인 것 κ°™μŠ΅λ‹ˆλ‹€.

λ°˜μ‘ν˜•