Skip to content

Commit 0ade889

Browse files
committed
docupdate
1 parent af02002 commit 0ade889

10 files changed

Lines changed: 1672 additions & 0 deletions

Doc/ko/01_akka_서비스_.md

Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
# Chapter 1: Akka 서비스
2+
3+
## 개요
4+
“Akka 서비스”는 여러 개의 액터 시스템(ActorSystem)을 쉽고 편리하게 만들어 관리할 수 있도록 돕는 핵심적인 구성 요소입니다. 액터(actor)는 동시에 많은 일이 벌어지는 상황에서 각자 메시지를 주고받으며 일을 처리하는 작은 단위라고 생각하시면 됩니다. 예를 들어, 여러 명의 아이들이 모여 노는데, 운동장(액터 시스템)을 만들어 아이들을 서로 다른 운동장에 배치할 수 있고, 필요한 순간에 특정 아이(액터)를 불러낼 수도 있습니다. 이렇게 나누어 관리하면 복잡한 동시성 문제를 단순화시킬 수 있습니다.
5+
6+
여기서는 “Akka 서비스”가 무엇을 하는지, 왜 필요한지, 그리고 실제로 어떻게 사용하는지 간단한 예시와 함께 알아보겠습니다.
7+
8+
---
9+
10+
## 왜 “Akka 서비스”가 필요한가?
11+
초보자 입장에서, 한 번에 모든 액터를 한 운동장 안에 몰아넣으면 쉽게 관리할 것 같지만, 점점 규모가 커지면 복잡해집니다. 새로운 기능을 추가하거나, 액터 간 충돌을 막아야 할 때 점점 골치 아파집니다. 그래서 필요한 만큼 운동장을 늘리고, 각 운동장마다 서로 다른 규칙(포트, 설정 등)을 적용할 수 있도록 지원해주는 것이 바로 “Akka 서비스”입니다.
12+
13+
### 주요 기능 한 눈에 보기
14+
1. **ActorSystem 생성**: 원하는 이름과 포트로 새로운 액터 시스템을 동적으로 만듭니다.
15+
2. **기본 시스템 설정**: 필요하다면 기본(default) 시스템을 지정해둘 수도 있습니다.
16+
3. **액터 등록 및 조회**: 생성된 액터(아이)를 편하게 등록하고, 언제든지 다시 불러올 수 있습니다.
17+
18+
---
19+
20+
## “Akka 서비스”를 간단히 살펴보기
21+
22+
### 핵심 클래스: AkkaService
23+
“Akka 서비스” 구현의 중심에는 “AkkaService” 클래스가 있습니다. 이 클래스는 두 개의 `Dictionary`를 통해 액터 시스템과 액터를 저장하고 관리합니다.
24+
25+
아래 코드는 “AkkaService” 클래스 중 일부를 발췌한 예시입니다:
26+
27+
```csharp
28+
public class AkkaService
29+
{
30+
private Dictionary<string, ActorSystem> actorSystems = new Dictionary<string, ActorSystem>();
31+
private Dictionary<string, IActorRef> actors = new Dictionary<string, IActorRef>();
32+
33+
// ...
34+
}
35+
```
36+
37+
여기서 `actorSystems`는 이름을 키로 하여 `ActorSystem`을 저장하고, `actors`는 특정 액터를 식별하는 키(이름)에 해당 `IActorRef`(액터 참조)를 매핑해둡니다.
38+
39+
---
40+
41+
### ActorSystem 생성하기
42+
실제 운동장을 만드는 과정(ActorSystem 생성)은 `CreateActorSystem` 메서드가 담당합니다. 다음 예시는 필수 로직만 간단히 보여줍니다:
43+
44+
```csharp
45+
public ActorSystem CreateActorSystem(string name, int port = 0)
46+
{
47+
if (!actorSystems.ContainsKey(name))
48+
{
49+
if (port == 0)
50+
{
51+
// 기본 설정을 사용하여 ActorSystem 생성
52+
actorSystems[name] = ActorSystem.Create(name);
53+
}
54+
else
55+
{
56+
// 포트 지정 시 리모트 설정 반영
57+
string akkaConfig = @"
58+
akka {
59+
actor { provider = remote }
60+
remote {
61+
dot-netty.tcp {
62+
port = $port
63+
hostname = ""127.0.0.1""
64+
}
65+
}
66+
}";
67+
68+
// $port를 실제 포트 번호로 치환
69+
akkaConfig = akkaConfig.Replace("$port", port.ToString());
70+
var config = ConfigurationFactory.ParseString(akkaConfig);
71+
72+
actorSystems[name] = ActorSystem.Create(name, config);
73+
}
74+
}
75+
else
76+
{
77+
throw new Exception($"{name} actorsystem has already been created.");
78+
}
79+
80+
return actorSystems[name];
81+
}
82+
```
83+
84+
#### 어떻게 동작하나요?
85+
1. `name`이라는 키로 이미 생성된 액터 시스템이 있으면 예외를 발생시킵니다.
86+
2. 없으면 포트가 0인지 확인하고, 0이라면 “기본 설정”을 통해 운동장(ActorSystem)을 만듭니다.
87+
3. 포트 번호가 주어지면 네트워크 설정(예: 리모트 액터)을 허용하는 특별한 운동장을 만듭니다.
88+
89+
---
90+
91+
### 생성된 ActorSystem 활용하기
92+
만들어진 액터 시스템에 액터를 등록하고 싶다면, 다음과 같은 방식을 사용할 수 있습니다.
93+
94+
```csharp
95+
// 새로운 ActorSystem 생성
96+
var actorSystem = myAkkaService.CreateActorSystem("MyPlayground");
97+
98+
// 액터 생성 후 등록
99+
IActorRef myNewActor = actorSystem.ActorOf<MyActor>("myNewActor");
100+
myAkkaService.AddActor("myActorKey", myNewActor);
101+
```
102+
103+
이 코드에서 “`myAkkaService`”는 미리 만들어 둔 `AkkaService`의 인스턴스라고 가정합니다.
104+
- `"MyPlayground"`라는 이름의 운동장을 새로 만들었습니다.
105+
- `ActorOf<T>` 메서드를 통해 액터를 만들고, `"myNewActor"`라는 별칭을 부여했습니다.
106+
- 마지막으로 `AddActor` 메서드에 `"myActorKey"`를 키로 사용해 우리가 만든 액터를 등록합니다.
107+
108+
등록된 액터는 언제든 다음과 같이 다시 불러올 수 있습니다:
109+
110+
```csharp
111+
var actorRef = myAkkaService.GetActor("myActorKey");
112+
```
113+
114+
---
115+
116+
## 내부 동작 흐름 살펴보기
117+
118+
다음은 사용자가 새로운 액터를 만들고 등록할 때 벌어지는 간단한 순서를 나타낸 시퀀스 다이어그램입니다.
119+
120+
```mermaid
121+
sequenceDiagram
122+
participant U as 사용자
123+
participant S as AkkaService
124+
participant A as ActorSystem
125+
participant AC as 특정 액터
126+
127+
U->>S: CreateActorSystem("MyPlayground")
128+
S->>S: Dictionary에 ActorSystem "MyPlayground" 등록
129+
S->>A: ActorSystem.Create("MyPlayground")
130+
U->>A: ActorSystem.ActorOf<MyActor>("myNewActor")
131+
U->>S: S.AddActor("myActorKey", myNewActor)
132+
S->>S: Dictionary에 액터 등록
133+
```
134+
135+
1. 사용자가 `CreateActorSystem`을 호출하면, “AkkaService”는 내부 `Dictionary`를 확인해 중복이 없는지 체크하고, 새 “ActorSystem”을 생성한 후 등록합니다.
136+
2. 사용자는 생성된 “ActorSystem”을 통해 액터를 생성합니다.
137+
3. 마지막으로 `AddActor`로 “AkkaService” 안에 해당 액터도 등록해두면, 필요한 시점에 바로 꺼내 쓸 수 있습니다.
138+
139+
---
140+
141+
## 내부 구현 조금 더 살펴보기
142+
아래 작은 코드 조각들은 “AkkaService” 클래스에서 액터 등록과 조회를 담당하는 부분입니다.
143+
144+
```csharp
145+
public void AddActor(string name, IActorRef actor)
146+
{
147+
if (!actors.ContainsKey(name))
148+
{
149+
actors[name] = actor;
150+
}
151+
}
152+
```
153+
- `actors`라는 Dictionary에 “이름”을 키로 하여 액터 참조(`IActorRef`)를 저장합니다.
154+
- 이미 동일한 키가 있으면 덮어쓰지 않도록 예외 처리를 하거나, 원하는 로직에 따라 동작시킬 수 있습니다.
155+
156+
```csharp
157+
public IActorRef GetActor(string name)
158+
{
159+
if (actors.ContainsKey(name))
160+
{
161+
return actors[name];
162+
}
163+
else
164+
{
165+
return null;
166+
}
167+
}
168+
```
169+
- 이름으로 등록된 액터가 있는지 찾아보고, 있으면 해당 액터를 반환합니다.
170+
- 없다면 `null`을 반환합니다(실무에서는 예외 처리를 하는 등 상황에 맞는 로직을 추가하는 경우가 많습니다).
171+
172+
---
173+
174+
## 정리 및 다음 장으로
175+
이 장에서는 “Akka 서비스”가 무엇이며 왜 필요한지, 그리고 기본적인 사용 방법을 살펴보았습니다.
176+
- 여러 액터 시스템을 자유롭게 만들고 포트를 설정할 수 있습니다.
177+
- 액터를 등록하고 필요할 때마다 간편하게 가져올 수 있습니다.
178+
179+
이제 다양한 액터 구현 방법을 살펴볼 차례입니다. 다음 장에서는 [기본 액터(BasicActor)](02_기본_액터_basicactor__.md)를 살펴보며 실제 액터가 어떻게 메시지를 주고받는지 알아보겠습니다.
180+
181+
---
182+
183+
Generated by [AI Codebase Knowledge Builder](https://github.com/The-Pocket/Tutorial-Codebase-Knowledge)
Lines changed: 166 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,166 @@
1+
# Chapter 2: 기본 액터(BasicActor)
2+
3+
[이전 장: Akka 서비스](01_akka_서비스_.md)
4+
5+
이전 장에서 여러 액터 시스템을 만들고 관리하는 방법을 살펴보았습니다. 이제 실제로 액터가 어떤 식으로 메시지를 주고받으며 동작하는지 배워볼 차례입니다. 이번 장에서는 “기본 액터(BasicActor)”를 통해 메시지 처리의 가장 간단한 예시를 살펴보겠습니다.
6+
7+
---
8+
9+
## 왜 “기본 액터”가 필요할까요?
10+
11+
초급 단계에서 액터를 배울 때, 메시지를 어떻게 주고받는지 직관적으로 알 수 있는 예시가 필요합니다. “기본 액터(BasicActor)”는 다음과 같은 상황을 가정해 볼 수 있습니다:
12+
13+
- 친구에게 “안녕?”이라는 메시지를 보내듯이, 누군가 액터에게 메시지를 전달하면 그에 맞춰 대응하는 응답을 돌려주거나, 다른 액터 혹은 로거(Logger)에게 내용을 넘깁니다.
14+
- 이 과정을 통해 액터가 받은 메시지를 어떻게 처리하고, 어떤 결과를 만드는지 직접 확인해볼 수 있습니다.
15+
16+
예를 들어, 누군가가 “BasicActor”에게 “안녕?”(string 타입 메시지)을 보내면, 이 액터는 “world”라는 답을 보낸다고 생각해보세요. 단순해 보이지만, 이 작은 단위에서 액터가 어떻게 반응해야 하는지를 배울 수 있습니다.
17+
18+
---
19+
20+
## 기본 개념 살펴보기
21+
22+
“기본 액터(BasicActor)”는 Akka.NET의 “ReceiveActor”를 상속하여 만들어집니다. “ReceiveActor”는 메시지 타입에 따라 해당 메시지를 처리하는 로직을 손쉽게 구성할 수 있도록 해줍니다.
23+
24+
다음은 “BasicActor”의 가장 간단한 코드 구조 예시입니다:
25+
26+
```csharp
27+
public class BasicActor : ReceiveActor
28+
{
29+
public BasicActor()
30+
{
31+
// 문자열 메시지를 받는 방식
32+
Receive<string>(msg =>
33+
{
34+
// 메시지를 처리한 뒤, 응답 또는 다른 액션을 수행
35+
Sender.Tell("world");
36+
});
37+
}
38+
}
39+
```
40+
41+
1. “ReceiveActor”를 상속받아서, 생성자 안에 `Receive<T>` 메서드를 사용해 T 타입의 메시지를 처리할 로직을 작성합니다.
42+
2. 위 예시에서는 문자열(string) 메시지가 들어왔을 때 `"world"`라는 응답을 보냅니다.
43+
44+
---
45+
46+
## 간단한 사용 예시
47+
48+
“기본 액터”가 있다면, 실제로 어떻게 메시지를 주고받는지 간단히 살펴보겠습니다. 아래 예시는 콘솔 프로그램 등에서 기본 액터를 사용해보는 과정입니다.
49+
50+
```csharp
51+
// 1) 액터 시스템 생성
52+
var actorSystem = ActorSystem.Create("BasicSystem");
53+
54+
// 2) BasicActor 인스턴스 생성
55+
var basicActor = actorSystem.ActorOf<BasicActor>("basicActor");
56+
57+
// 3) 메시지 전송
58+
basicActor.Tell("안녕?");
59+
60+
// 4) 응답은 Sender (여기서는 간단히 actorSystem.ActorOf(...) 등) 참조를 통해 받을 수 있음
61+
```
62+
63+
- 1단계: “BasicSystem”이라는 액터 시스템을 만듭니다(운동장 생성).
64+
- 2단계: “기본 액터”(BasicActor)를 “basicActor”라는 이름으로 선언합니다.
65+
- 3단계: “안녕?”이라는 문자열 메시지를 보냅니다.
66+
- 4단계: 메시지를 받은 “기본 액터”가 “world”를 응답합니다(테스트 환경 등을 통해 확인할 수 있습니다).
67+
68+
---
69+
70+
## 조금 더 복잡한 메시지 처리
71+
72+
문자열뿐 아니라, 여러 가지 다른 타입의 메시지를 동시에 받도록 만들 수도 있습니다. 예를 들어 IActorRef 타입 메시지가 들어왔을 때 특정 참조를 저장하고, Todo 메시지가 들어왔을 때는 그 참조에게 다시 전달해주는 식으로 다양하게 구성할 수 있습니다.
73+
74+
다음 코드는 “BasicActor” 내부에서 두 가지 메시지를 함께 처리하는 간단한 예시입니다(실제 구현의 일부분을 축소):
75+
76+
```csharp
77+
public class BasicActor : ReceiveActor
78+
{
79+
private IActorRef? testProbe; // 다른 액터의 참조를 저장할 변수
80+
81+
public BasicActor()
82+
{
83+
// IActorRef 타입 메시지를 받으면 해당 참조를 저장
84+
Receive<IActorRef>(actorRef =>
85+
{
86+
testProbe = actorRef;
87+
});
88+
89+
// Todo 메시지를 받으면 저장해둔 testProbe에게 전달
90+
Receive<Todo>(msg =>
91+
{
92+
// testProbe가 null이 아니라면 전달
93+
if (testProbe != null)
94+
{
95+
testProbe.Tell(msg);
96+
}
97+
});
98+
}
99+
}
100+
```
101+
102+
1. `IActorRef? testProbe`라는 변수를 두어서, “어떤 액터를 대신 참조”하도록 저장해둘 수 있습니다.
103+
2. `Receive<IActorRef>` 구문에서 그 참조를 받으면 `testProbe`에 저장합니다.
104+
3. 이후 `Receive<Todo>` 같은 다른 메시지가 들어오면, 그 메시지를 `testProbe`에게 “위임”할 수 있습니다.
105+
106+
---
107+
108+
## 내부 동작 흐름 미리 살펴보기
109+
110+
누군가가 문자열이나 특정 메시지를 액터에게 보내는 과정을 시퀀스 다이어그램으로 간단히 표현해보겠습니다.
111+
112+
```mermaid
113+
sequenceDiagram
114+
participant S as 송신자
115+
participant B as BasicActor
116+
participant T as (testProbe) 액터
117+
118+
S->>B: "안녕?"
119+
B->>S: "world"
120+
S->>B: Todo 메시지
121+
B->>T: Todo 메시지 전달
122+
```
123+
124+
1. 송신자가 “BasicActor”에게 문자열 메시지를 보냅니다.
125+
2. “BasicActor”는 즉시 `"world"`라는 응답을 송신자에게 돌려줍니다.
126+
3. 송신자가 다시 “BasicActor”에게 `Todo` 메시지를 보내면, “BasicActor”는 저장해둔 `testProbe`에게 그대로 메시지를 넘깁니다.
127+
128+
---
129+
130+
## 더 자세한 내부 구현 (생명주기)
131+
132+
“BasicActor”에는 미리 정의된 “생명주기(Lifecycle)” 메서드들이 있습니다. 예를 들어 액터가 시작할 때(`PreStart`), 종료할 때(`PostStop`) 실행되는 로직을 넣어둘 수 있습니다. 실제 코드 일부(축소) 예시는 다음과 같습니다:
133+
134+
```csharp
135+
protected override void PreStart()
136+
{
137+
// 액터가 생성될 때 실행할 코드
138+
// 여기서는 단순히 로그 기록
139+
Context.GetLogger().Info("BasicActor is starting.");
140+
base.PreStart();
141+
}
142+
143+
protected override void PostStop()
144+
{
145+
// 액터가 종료될 때 실행할 코드
146+
Context.GetLogger().Info("BasicActor is stopping.");
147+
base.PostStop();
148+
}
149+
```
150+
151+
- “PreStart”: 액터가 막 생성될 때 초기화 작업을 수행하거나, 로깅을 할 수 있습니다.
152+
- “PostStop”: 액터가 정리되어야 할 때 리소스를 반환하거나, 종료 메시지를 남길 수도 있습니다.
153+
154+
---
155+
156+
## 정리 및 다음 단계
157+
158+
이 장에서는 “기본 액터(BasicActor)”를 예로 들며 액터가 메시지를 처리하는 가장 단순한 방법을 살펴보았습니다. 액터가 어떻게 메시지를 받고, 응답하거나 다른 액터에게 메시지를 넘기는지 이해했다면, 다음 단계로는 메시지를 더 체계적으로 관리할 필요가 생깁니다.
159+
160+
다음 장에서는 [이슈 추적 메일박스(IssueTrackerMailbox)](03_이슈_추적_메일박스_issuetrackermailbox__.md)를 살펴봅니다. 메일박스를 통해 액터로 들어오는 메시지를 어떤 식으로 우선순위나 이슈 트래킹에 맞춰 관리할 수 있는지 알아보겠습니다.
161+
162+
“기본 액터”는 작고 간단해보일 수 있지만, 메시지 기반으로 동작하는 핵심 아이디어를 처음 접하는 좋은 출발점이 되어줄 것입니다.
163+
164+
---
165+
166+
Generated by [AI Codebase Knowledge Builder](https://github.com/The-Pocket/Tutorial-Codebase-Knowledge)

0 commit comments

Comments
 (0)