이벤트 다루기
ํ๋ ์์คํ ์์ DDD(Domain-Driven Design) ๋ฐ ํด๋ฆฐ ์ํคํ ์ฒ(Clean Architecture)์ ๊ฐ์ ์ํคํ ์ฒ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๋ฐ๋ฅด๋ ๊ฒฝ์ฐ, ์ด๋ฒคํธ๋ ์ํ ๋ณ๊ฒฝ์ ๋ชจ๋ธ๋งํ๊ณ ๊ตฌ์ฑ ์์ ๋๋ ์์คํ ๊ฐ ๋น๋๊ธฐ ํต์ ์ ์ํํ๋ ๋ฐ ํ์์ ์ธ ๋ฉ์ปค๋์ฆ์ ๋๋ค. ์ด๋ฒคํธ๋ ์ ํ๋ฆฌ์ผ์ด์ ๋๋ฉ์ธ์์ ์ด๋ฏธ ๋ฐ์ํ ์ผ์ด๋ฉฐ, ์์คํ ์ ๋ค๋ฅธ ๋ถ๋ถ์ด๋ ์ธ๋ถ ์๋น์ค์์ ๊ด์ฌ์ ๊ฐ์ง ์ ์์ต๋๋ค. ๋ณด๊ฐ: This section also covers shadow entities and the Transactional Outbox flow with DDD, MediatR, MassTransit, RabbitMQ, Hangfire, and Unit of Work for reliable messaging.
๋๋ฉ์ธ ์ด๋ฒคํธ
๋๋ฉ์ธ ์ด๋ฒคํธ๋ ์ ํ๋ฆฌ์ผ์ด์ ์ปจํ ์คํธ ๋ด์์ ๋ฐ์ํ ์ค์ํ ์ฌ์ค์ ๋ํ๋ ๋๋ค. ์ด ์ด๋ฒคํธ๋ ์์คํ ๋ด๋ถ์์ ์์ฑ ๋ฐ ์๋น๋๋ฉฐ, ์ํ ๋ณ๊ฒฝ์ ๋์จํ๊ฒ ๊ฒฐํฉ๋ ๋ฐฉ์์ผ๋ก ์ ํํ ์ ์์ต๋๋ค. ์ฆ, ๊ฐ์ฒด๋ค์ด ์๋ก๋ฅผ ์ง์ ์ ํ์๊ฐ ์์ต๋๋ค.
๋๋ฉ์ธ ์ด๋ฒคํธ๋ฅผ ์ธ์ ์ฌ์ฉํด์ผ ํ๋์?
- ์ด๋ค ์์ ์ด ๋๋ฉ์ธ์ ์ค์ํ ๋ณํ๋ฅผ ์ผ์ผํค๊ณ , ์์คํ ์ ๋ค๋ฅธ ๋ถ๋ถ์ ์๋ฆผ ๋๋ ํธ๋ฆฌ๊ฑฐ๊ฐ ํ์ํ ๋.
- ๋๋ฉ์ธ ๋ชจ๋ธ์ ์์ง๋ ฅ์ ์ ์งํ๊ณ , ์๋ก ์ง์ ์์กดํ์ง ์๊ณ ๋ ๋ค์ํ ํ๋ก์ธ์ค๋ฅผ ํธ๋ฆฌ๊ฑฐํ ์ ์๋๋ก ํ ๋.
Lino์์๋ ์๋ก์ด ๋๋ฉ์ธ ์ด๋ฒคํธ๋ฅผ ์ฝ๊ฒ ์์ฑํ ์ ์์ต๋๋ค. ๋ค์ ๋ช ๋ น์ ์คํํ์ธ์:
lino event new lino event new --name <EventName> --service <ServiceName> --module <ModuleName> --entity <EntityName> lino event edit --service <ServiceName> --module <ModuleName> --entity <EntityName> lino event list --service <ServiceName> --module <ModuleName> --entity <EntityName>
CLI ๋ง๋ฒ์ฌ๊ฐ ๋ค์์ ์์ฒญํฉ๋๋ค:
- ์๋น์ค โ ์ด๋ฒคํธ๊ฐ ์์ฑ๋ ์๋น์ค.
- ๋ชจ๋ โ ์ด๋ฒคํธ๊ฐ ์์ฑ๋ ๋ชจ๋(๋ชจ๋ํ ์๋น์ค๋ง ํด๋น).
- ์ํฐํฐ โ ์ด๋ฒคํธ๊ฐ ์์ฑ/์ฐ๊ฒฐ๋ ์ํฐํฐ.
- ์ด๋ฒคํธ ์ ํ โ ๋๋ฉ์ธ ์ด๋ฒคํธ ๋๋ ํตํฉ ์ด๋ฒคํธ.
- ์ด๋ฒคํธ ์ด๋ฆ โ ๋๋ฉ์ธ์์ ์ฌ์ฉ๋๋ฉฐ ์ํฐํฐ์ ์ฐ๊ฒฐ๋๋ ์ด๋ฆ.
์์
User ์ํฐํฐ์ ์ฐ๊ฒฐ๋ ๋๋ฉ์ธ ์ด๋ฒคํธ UserCreated๋ฅผ ์์ฑํ๋ฉด,
์์คํ
์ ์๋์ผ๋ก UserCreatedDomainEvent๋ผ๋ ์ด๋ฆ์ ์ด๋ฒคํธ๋ฅผ ์์ฑํฉ๋๋ค.
์ด ์ด๋ฆ์ ์ด๋ฒคํธ๋ฅผ ์๋นํ๋ ์์คํ
์ ์ด๋ ๋ถ๋ถ์์๋ ์ฌ์ฉ์ ์์ฑ ์์
์ด ์ด๋ฏธ ์๋ฃ๋์์์ ๋ช
ํํ ๋ณด์ฌ์ค๋๋ค.
Lino๊ฐ ์์ฑํ ๊ตฌ์กฐ:
<ProjectName>/
โโโ src/
โโโ Services/
โโโ <ServiceName>/
โโโ Domain/
โโโ <ProjectName>.<ServiceName>.Domain.csproj
โโโ Aggregates/
โโโ Users/
โโโ User.cs
โโโ Errors/
โโโ Events/
โ โโโ UserCreatedDomainEvent.cs
โโโ Repositories/
โโโ Resources/
Technical flow in Lino
- The aggregate registers an
IDomainEventwithRegisterDomainEvent. - The command handler saves through
IUnitOfWork, preferablySaveChangesInTransactionAsyncwhen events are involved. - The Unit of Work persists changes and publishes events through MediatR.
- A domain handler can register an integration event in
IOutbox.
Events are not commands; use past-tense names such as UserCreatedDomainEvent.
๋๋ฉ์ธ ์ด๋ฒคํธ ํธ๋ค๋ฌ
Domain Event Handler๋ ๋๋ฉ์ธ ์ด๋ฒคํธ์ ๋ฐ์ํ๊ณ ์ ํ๋ฆฌ์ผ์ด์ ๋ด๋ถ ์ํ์ ๊ด๋ จ๋ ์์ ์ ์ํํ๋ ํด๋์ค์ด๋ฉฐ, ํญ์ ๋์ผํ ํธ๋์ญ์ ์ปจํ ์คํธ ๋ด์์ ์คํ๋ฉ๋๋ค.
์ด๋ฌํ ํธ๋ค๋ฌ์ ์ฃผ์ ๋ชฉ์ ์ ์์คํ ์ ์์ง๋ ฅ ์๊ณ ๋์จํ๊ฒ ๊ฒฐํฉ๋ ์ํ๋ก ์ ์งํ์ฌ ์ํฐํฐ๋ ์ ๊ทธ๋ฆฌ๊ฒ์ดํธ์ ํต์ฌ ๋ก์ง์ ๊ณผ๋ถํํ์ง ์๊ณ ์ถ๊ฐ ๊ท์น์ ์ ์ฉํ ์ ์๋๋ก ํ๋ ๊ฒ์ ๋๋ค.
์๋ฅผ ๋ค์ด User๋ฅผ ์์ฑํ ํ ํต๊ณ๋ฅผ ์
๋ฐ์ดํธํ๊ฑฐ๋ ๋ด๋ถ ๋ก๊ทธ๋ฅผ ์์ฑํ๊ฑฐ๋ ๋ค๋ฅธ ์ ๊ทธ๋ฆฌ๊ฒ์ดํธ์ ์๋ฆผ์ ๋ณด๋ด์ผ ํ ์ ์์ต๋๋ค.
์ด๋ฌํ ์์
์ ๋๋ฉ์ธ ๋ด์์ ์๋ฏธ๊ฐ ์์ผ๋ฉฐ ๋๊ธฐ์ ์ผ๋ก ์ํ๋ ์ ์์ด ์ฆ๊ฐ์ ์ธ ์ผ๊ด์ฑ์ ๋ณด์ฅํฉ๋๋ค.
๊ทธ๋ฌ๋ ์ธ๋ถ ๋ฆฌ์์ค์ ์์กดํ๋ ์์ โ ์ด๋ฉ์ผ ์ ์ก ๋๋ ์๋ํํฐ API ํธ์ถ ๋ฑ โ ์ ๋๋ฉ์ธ ์ด๋ฒคํธ์์ ์ง์ ์ํํด์๋ ์ ๋ฉ๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ํธ๋์ญ์ ์ด ๋๋ฆฌ๊ฑฐ๋ ๋ถ์์ ํ ์์ ์ ๋ฌถ์ด๊ฒ ๋๊ธฐ ๋๋ฌธ์ ๋๋ค. ์ด ๊ฒฝ์ฐ ๋๋ฉ์ธ์ ํตํฉ ์ด๋ฒคํธ(Outbox์ ๊ธฐ๋ก)๋ฅผ ์์ฑํ๊ณ ๋์ค์ ๋น๋๊ธฐ์ ์ด๊ณ ํ๋ณต๋ ฅ ์๊ฒ ์ฒ๋ฆฌ๋ฉ๋๋ค.
์ฃผ์ ํน์ง:
- ์ด๋ฒคํธ์ ๋ฐ์ํ์ง๋ง ์ ๋ ์์ ํ์ง ์์ต๋๋ค.
- ๋๋ฉ์ธ ์ผ๊ด์ฑ๊ณผ ๊ด๋ จ๋ ์ธํ๋ก์ธ์ค ์์ ๋ง ์ํํฉ๋๋ค.
- ๋ชจ๋ ์์ ์ด ๋์ผํ ํธ๋์ญ์ ๋ด์์ ์คํ๋๋๋ก ๋ณด์ฅํฉ๋๋ค.
์๋ก์ด ๋๋ฉ์ธ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ์์ฑํ๋ ค๋ฉด ๋ค์ ๋ช ๋ น์ด๋ฅผ ์คํํ์ธ์:
lino event-handler new
CLI ๋ง๋ฒ์ฌ๊ฐ ๋ค์์ ์์ฒญํฉ๋๋ค:
- ์๋น์ค โ ์ด๋ฒคํธ ํธ๋ค๋ฌ๊ฐ ์์ฑ๋ ์๋น์ค.
- ๋ชจ๋ โ ์ด๋ฒคํธ ํธ๋ค๋ฌ๊ฐ ์์ฑ๋ ๋ชจ๋(๋ชจ๋ํ ์๋น์ค์์๋ง ํด๋น).
- ์ํฐํฐ โ ์ด๋ฒคํธ ํธ๋ค๋ฌ๊ฐ ์์ฑ๋ ์ํฐํฐ.
- ์ด๋ฒคํธ ์ ํ โ ๋๋ฉ์ธ ์ด๋ฒคํธ ๋๋ ํตํฉ ์ด๋ฒคํธ.
- ์ด๋ฒคํธ โ ์๋น๋ ์ด๋ฒคํธ.
- ์ด๋ฒคํธ ํธ๋ค๋ฌ ์ด๋ฆ โ ์ํฐํฐ ๋ฐ ๋๋ฉ์ธ ์ด๋ฒคํธ์ ์ฐ๊ฒฐ๋ ์ด๋ฆ.
์์
User ์ํฐํฐ์ UserCreatedDomainEvent ์ด๋ฒคํธ์ ์ฐ๊ฒฐ๋ ๋๋ฉ์ธ ์ด๋ฒคํธ ํธ๋ค๋ฌ UserCreated๋ฅผ ์์ฑํ๋ฉด, ์์คํ
์ ์๋์ผ๋ก UserCreatedDomainEventHandler๋ผ๋ ์ด๋ฆ์ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ์์ฑํฉ๋๋ค.
Lino๊ฐ ์์ฑํ ๊ตฌ์กฐ:
<ProjectName>/
โโโ src/
โโโ Services/
โโโ <ServiceName>/
โโโ Application/
โโโ <ProjectName>.<ServiceName>.Application.csproj
โโโ UseCases/
โโโ Users/
โโโ Commands/
โโโ EventHandlers/
โ โโโ Domain/
โ โโโ UserCreatedDomainEventHandler.cs
โโโ Logging/
โโโ Queries/
โโโ Resources/
Technical responsibilities
- Implements
IDomainEventHandlerand reacts inside the application boundary. - Runs internal consistency, logging, tracing, or integration registration work.
- Uses
IOutbox.RegisterIntegrationEventfor reliable messages. - Keeps the business change and
OutboxMessagein the same transaction.
ํตํฉ ์ด๋ฒคํธ
ํตํฉ ์ด๋ฒคํธ๋ ์ค์ํ ์ผ์ด ๋ฐ์ํ์์ ์๋ฆฌ๋ ๋ฉ์์ง์ด๋ฉฐ, ์ธ๋ถ ์์คํ ์ด๋ ๋ค๋ฅธ ๋ง์ดํฌ๋ก์๋น์ค์ ๊ณต์ ํด์ผ ํฉ๋๋ค.
๋๋ฉ์ธ ์ด๋ฒคํธ์ ๋ฌ๋ฆฌ, ์ฌ๊ธฐ์์ ๋ชฉ์ ์ ์์คํ ๊ฐ ํต์ ๋ฐ ์ํ ๋๊ธฐํ์ ๋๋ค.
ํตํฉ ์ด๋ฒคํธ๋ฅผ ์์ฑํ ๋:
- ์์คํ ์ ๋ณ๊ฒฝ ์ฌํญ์ ๋ค๋ฅธ ์์คํ ์ ๋ฐ์ํด์ผ ํ ๋.
- ๋ง์ดํฌ๋ก์๋น์ค๊ฐ ๋ณ๊ฒฝ ์ฌํญ์ ๊ฒ์ํ์ฌ ๋ค๋ฅธ ๋ง์ดํฌ๋ก์๋น์ค๊ฐ ๋ฐ์ํด์ผ ํ ๋.
๋๋ฉ์ธ ์ด๋ฒคํธ์ ํตํฉ ์ด๋ฒคํธ์ ์ฃผ์ ์ฐจ์ด์ :
| ํญ๋ชฉ | ๋๋ฉ์ธ ์ด๋ฒคํธ | ํตํฉ ์ด๋ฒคํธ |
|---|---|---|
| ๋์ | ๋ด๋ถ | ์ธ๋ถ |
| ๊ฒฐํฉ๋ | ๋ฎ์ (๋ด๋ถ) | ํ์ (์์คํ ๊ฐ) |
| ์ฒ๋ฆฌ ์๊ฐ | ์ฆ์ | ๋น๋๊ธฐ์ผ ์ ์์ผ๋ฉฐ, ์ ๋ฌ ๋ณด์ฅ ํฌํจ |
| ์์์ฑ ํ์ ์ฌ๋ถ | ํ์ ์๋ | ์ (์ ๋ขฐ์ฑ๊ณผ ๋ณต์๋ ฅ ํ๋ณด๋ฅผ ์ํด) |
Lino์์๋ ์ ํตํฉ ์ด๋ฒคํธ๋ฅผ ์ฝ๊ฒ ์์ฑํ ์ ์์ต๋๋ค. ๋ค์ ๋ช ๋ น์ด๋ฅผ ์คํํ์ธ์:
lino event new lino event new --name <EventName> --service <ServiceName> --module <ModuleName> --entity <EntityName> lino event list --service <ServiceName> --module <ModuleName> --entity <EntityName>
CLI ๋ง๋ฒ์ฌ๊ฐ ์์ฒญํ๋ ํญ๋ชฉ:
- ์๋น์ค โ ์ด๋ฒคํธ๋ฅผ ์์ฑํ ์๋น์ค.
- ๋ชจ๋ โ ์ด๋ฒคํธ๋ฅผ ์์ฑํ ๋ชจ๋ (๋ชจ๋ํ ์๋น์ค์์๋ง).
- ์ํฐํฐ โ ์ด๋ฒคํธ๋ฅผ ์์ฑ/์ฐ๊ฒฐํ ์ํฐํฐ.
- ์ด๋ฒคํธ ์ ํ โ ๋๋ฉ์ธ ์ด๋ฒคํธ ๋๋ ํตํฉ ์ด๋ฒคํธ.
- ์ด๋ฒคํธ ์ด๋ฆ โ ์ํฐํฐ์ ์ฐ๊ฒฐ๋ ํตํฉ ์ด๋ฒคํธ ์ด๋ฆ.
์์
User ์ํฐํฐ์ ์ฐ๊ฒฐ๋ ํตํฉ ์ด๋ฒคํธ UserCreated๋ฅผ ์์ฑํ๋ฉด, ์์คํ
์ ์๋์ผ๋ก UserCreatedIntegrationEvent๋ผ๋ ์ด๋ฆ์ ์ด๋ฒคํธ๋ฅผ ์์ฑํฉ๋๋ค.
์ด ์ด๋ฆ์ ์ด๋ฒคํธ๋ฅผ ์๋นํ๋ ์์คํ
์ ๋ชจ๋ ๋ถ๋ถ์์ ์ฌ์ฉ์ ์์ฑ ์์
์ด ์ด๋ฏธ ์๋ฃ๋์์์ ๋ช
ํํ๊ฒ ๋ํ๋
๋๋ค.
Lino๊ฐ ์์ฑํ ๊ตฌ์กฐ:
<ProjectName>/
โโโ src/
โโโ Services/
โโโ <ServiceName>/
โโโ Integration.Events/
โโโ <ProjectName>.<ServiceName>.Integration.Events.csproj
โโโ Users/
โโโ UserCreatedIntegrationEvent.cs
Reliable publication
An integration event implements IIntegrationEvent and crosses boundaries between modules, services, or systems. The application registers the event in IOutbox, the Unit of Work persists an OutboxMessage, and a Hangfire worker later publishes it through MassTransit/RabbitMQ.
ํตํฉ ์ด๋ฒคํธ ํธ๋ค๋ฌ
Integration Event Handler ๋ ์ผ๋ฐ์ ์ผ๋ก ๋ค๋ฅธ ์๋น์ค๋ ์ปจํ ์คํธ์์ ๋ฐํ๋ Integration Event ๋ฅผ ์๋นํ๊ณ , ์์ ์ ๋๋ฉ์ธ ๋ด์์ ํน์ ์์ ์ ์ํํ๋ ํด๋์ค์ ๋๋ค.
์ด๋ฌํ ํธ๋ค๋ฌ๋ RabbitMQ, Kafka, Azure Service Bus ๋ฑ๊ณผ ๊ฐ์ ๋ฉ์์ง ๋ฉ์ปค๋์ฆ์ ํตํด ์ด๋ฒคํธ๋ฅผ ์์ ํ๋ฉฐ, ์ผ๋ฐ์ ์ผ๋ก Outbox ํจํด๊ณผ ํจ๊ป ์ฌ์ฉ๋์ด ์์ ์ ์ธ ์ ๋ฌ๊ณผ ๋น๋๊ธฐ ์ฒ๋ฆฌ๋ฅผ ๋ณด์ฅํฉ๋๋ค.
์๋ฅผ ๋ค์ด, Identity ์๋น์ค์์ UserCreated ์ด๋ฒคํธ๋ฅผ ๋ฐํํ๋ฉด, ๋ค๋ฅธ ์ปจํ
์คํธ์ ํด๋น ํธ๋ค๋ฌ๋
ํ์ ์ด๋ฉ์ผ์ ๋ณด๋ด๊ฑฐ๋ ์ธ๋ถ API๋ฅผ ํธ์ถํ๋ ๋ฑ์ ๋ฐ์์ ์ํํ ์ ์์ต๋๋ค.
์ด๋ฌํ ์์
์ ๋๋ฆฌ๊ฑฐ๋ ์คํจํ ์ ์์ง๋ง, ๋ฉ์ธ ํธ๋์ญ์
์ธ๋ถ์์ ์ฒ๋ฆฌ๋๋ฏ๋ก ์ ํ๋ฆฌ์ผ์ด์
์ ๋ด๋ถ ์ผ๊ด์ฑ์๋ ์ํฅ์ ์ฃผ์ง ์์ต๋๋ค.
์ฃผ์ ํน์ง:
- ๋ค๋ฅธ ์ปจํ ์คํธ์ ๊ด๋ จ๋ ๋น์ฆ๋์ค ์ฌ์ค์ ๋ํ๋ด๋ ์ด๋ฒคํธ์ ๋ฐ์ํฉ๋๋ค.
- ๋๋ฆฌ๊ฑฐ๋ ์ธ๋ถ ์์ (์: ์ด๋ฉ์ผ ๋ฐ์ก, API ํธ์ถ)์ ์ํํฉ๋๋ค.
- ๋น๋๊ธฐ์ ์ด๊ณ ๋ณต์๋ ฅ ์๊ฒ ์ฒ๋ฆฌ๋๋ฉฐ, ์ข ์ข ์ฌ์๋ ๋ฐ ๋ชจ๋ํฐ๋ง์ด ํฌํจ๋ฉ๋๋ค.
- ์ธ๋ถ ์คํจ๊ฐ ์๋ ๋๋ฉ์ธ ํธ๋์ญ์ ์ ์ํฅ์ ์ฃผ์ง ์๋๋ก ๋ณด์ฅํฉ๋๋ค.
- ๋ฐ์ด๋๋ ์ปจํ ์คํธ ๋ฐ ๋ถ์ฐ ์์คํ ๊ฐ์ ํตํฉ์ ์ฉ์ดํ๊ฒ ํฉ๋๋ค.
์ ํตํฉ ์ด๋ฒคํธ ํธ๋ค๋ฌ๋ฅผ ์์ฑํ๋ ค๋ฉด ๋ค์ ๋ช ๋ น์ ์คํํ์ธ์:
lino event-handler new lino event-handler new --name <EventHandlerName> --service <ServiceName> --module <ModuleName> --entity <EntityName> lino event-handler list --service <ServiceName> --module <ModuleName> --entity <EntityName>
CLI ๋ง๋ฒ์ฌ๊ฐ ์์ฒญํ๋ ํญ๋ชฉ:
- ์๋น์ค โ ์ด๋ฒคํธ ํธ๋ค๋ฌ๊ฐ ์์ฑ๋ ์๋น์ค.
- ๋ชจ๋ โ ์ด๋ฒคํธ ํธ๋ค๋ฌ๊ฐ ์์ฑ๋ ๋ชจ๋(๋ชจ๋ํ ์๋น์ค๋ง ํด๋น).
- ์ํฐํฐ โ ์ด๋ฒคํธ ํธ๋ค๋ฌ๊ฐ ์์ฑ๋ ์ํฐํฐ.
- ์ด๋ฒคํธ ์ ํ โ ๋๋ฉ์ธ ์ด๋ฒคํธ ๋๋ ํตํฉ ์ด๋ฒคํธ.
- ์๋น์ค โ ์๋นํ ์ด๋ฒคํธ๊ฐ ์กด์ฌํ๋ ์๋น์ค.
- ๋ชจ๋ โ ์๋นํ ์ด๋ฒคํธ๊ฐ ์กด์ฌํ๋ ๋ชจ๋(๋ชจ๋ํ ์๋น์ค๋ง ํด๋น).
- ์ํฐํฐ โ ์๋นํ ์ด๋ฒคํธ๊ฐ ์กด์ฌํ๋ ์ํฐํฐ.
- ์ด๋ฒคํธ โ ์๋นํ ์ด๋ฒคํธ.
- ์ด๋ฒคํธ ํธ๋ค๋ฌ ์ด๋ฆ โ ์ํฐํฐ ๋ฐ ํตํฉ ์ด๋ฒคํธ์ ์ฐ๊ฒฐ๋ ์ด๋ฆ.
์์
User ์ํฐํฐ ๋ฐ UserCreatedIntegrationEvent ์ด๋ฒคํธ์ ์ฐ๊ฒฐ๋ ํตํฉ ์ด๋ฒคํธ ํธ๋ค๋ฌ
SendEmailOnUserCreated ๋ฅผ ์์ฑํ๋ฉด, ์์คํ
์ ์๋์ผ๋ก SendEmailOnUserCreatedIntegrationEventHandler ๋ผ๋ ์ด๋ฆ์ ํธ๋ค๋ฌ๋ฅผ ์์ฑํฉ๋๋ค.
Lino๊ฐ ์์ฑํ ๊ตฌ์กฐ:
<ProjectName>/
โโโ src/
โโโ Services/
โโโ <ServiceName>/
โโโ Application/
โโโ <ProjectName>.<ServiceName>.Application.csproj
โโโ UseCases/
โโโ Users/
โโโ Commands/
โโโ EventHandlers/
โ โโโ Integration/
โ โโโ SendEmailOnUserCreatedIntegrationEventHandler.cs
โโโ Logging/
โโโ Queries/
โโโ Resources/
Operational guidance
- Implements
IIntegrationEventHandlerand consumes messages with MassTransit. - Does not read the producer database directly.
- Updates local state, projections, or shadow entities.
- Should be idempotent because retries and duplicate messages can happen.
Shadow Entities
shadow entity๋ ์์ ์๊ฐ ๋ค๋ฅธ ๋ชจ๋์ด๋ ์๋น์ค์ ์๋ ๋ฐ์ดํฐ๋ฅผ ๋ก์ปฌ์ ์ต์ํ์ผ๋ก, ํต์ ๋ ๋ฐฉ์์ผ๋ก ๋ณต์ฌํ ๊ฒ์ ๋๋ค. consumer๊ฐ producer ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ง์ ์ ๊ทผํ์ง ์๊ณ ์ฐธ์กฐ ๋ฐ์ดํฐ๋ฅผ ์กฐํ, ๊ฒ์ฆ ๋๋ ํ์ํด์ผ ํ ๋ ๊ฒฐํฉ๋๋ฅผ ๋ฎ์ถ๊ธฐ ์ํด ์ฌ์ฉํฉ๋๋ค.
Shadow Entities๋ eventual consistency๋ฅผ ํ์ฉํ ์ ์์ ๋ ์ ์ฉํฉ๋๋ค. producer๊ฐ integration event๋ฅผ ๊ฒ์ํ๊ณ , ๋ฉ์์ง๋ Outbox์ ์ ์ฅ๋๋ฉฐ, worker๊ฐ bus์ ๊ฒ์ํ๊ณ , consumer๋ integration event handler๋ฅผ ํตํด ๋ก์ปฌ ๋ณต์ฌ๋ณธ์ ๊ฐฑ์ ํฉ๋๋ค.
lino shadow-entity new lino event new lino event-handler new
์ด ๋ช
๋ น์ lino shadow new alias๋ก๋ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋ํํ ํ๋ฆ์์ Lino๋ ๋์ ์๋น์ค ๋๋ ๋ชจ๋, ์๋ณธ entity, ๋ณต์ฌํ properties๋ฅผ ๋ฌป์ต๋๋ค. ์ด๋ฅผ ํตํด identifier type, ํ์ ์ฌ๋ถ, string ๊ธธ์ด, ๊ธฐ๋ณธ references๋ฅผ ์๋์ผ๋ก ๋ค์ ๋ง๋ค ํ์๊ฐ ์ค์ด๋ค๊ณ source์ consumer ์ฌ์ด์ ๋ถ์ผ์น๋ฅผ ์ค์ผ ์ ์์ต๋๋ค.
shadow entity๋ ์ ์ฒด ๋ณต์ ๋ณธ์ด ์๋๋๋ค. Catalog ๋ชจ๋์ด Tenancy์ Security์ ๋ฐ์ดํฐ๋ฅผ ์๋นํ๋ ์์์ catalog๋ Tenant.Id, Tenant.Slug, User.Id, User.Email, User.TenantId๋ง ์ ์งํ ์ ์์ต๋๋ค. ์๋ user entity์๋ hash, confirmation, tokens, dates ๋ฐ catalog context์ ์ํ์ง ์๋ ๋ค๋ฅธ ๋ด๋ถ ํ๋๊ฐ ๊ณ์ ํฌํจ๋ฉ๋๋ค.
์ฌ์ฉํ ๋
- consumer๊ฐ ๋ค๋ฅธ context์ ์ํ entity์ ์ผ๋ถ ํ๋๋ง ํ์๋ก ํ ๋.
- ๊ท์น์ด producer ๋ณ๊ฒฝ๊ณผ consumer ์ ๋ฐ์ดํธ ์ฌ์ด์ ์์ ์ง์ฐ์ ํ์ฉํ ๋.
- producer ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ฅผ ์ง์ ์ฝ๋ ๊ฒ์ด ๋ชจ๋์ด๋ ์๋น์ค ๊ฐ์ ๋ถ์ ์ ํ ๊ฒฐํฉ์ ๋ง๋ค ๋.
- grids, filters, local validations ๋๋ projections๊ฐ ์ธ๋ถ ์ฐธ์กฐ ๋ฐ์ดํฐ๋ฅผ ํ์๋ก ํ ๋.
ํผํด์ผ ํ ๋
- ๊ท์น์ด ์ฆ์ ๊ฐฑ์ ๋ ๋ฐ์ดํฐ๋ฅผ ์๊ตฌํ๊ณ eventual consistency๋ฅผ ํ์ฉํ์ง ์์ ๋.
- ๋ก์ปฌ ๋ณต์ฌ๋ณธ์ด ์๋ aggregate์ ์ ์ฒด ๋ณต์ ๋ณธ์ด ๋ ๋.
- consumer๊ฐ producer์ ์ํ invariants์ ์์กดํ๊ธฐ ์์ํ ๋.
๊ถ์ฅ ํ๋ฆ
- consumer์ ํ์ํ ํ๋๋ง ํฌํจํ๋๋ก shadow entity๋ฅผ ๋ชจ๋ธ๋งํฉ๋๋ค.
- producer๊ฐ ๊ฒ์ํ๋ integration event๋ฅผ ๋ง๋ค๊ฑฐ๋ ์ ํํฉ๋๋ค.
- consumer์ integration event handler๋ฅผ ๋ง๋ญ๋๋ค.
- producer key ๋๋ natural identifier๋ฅผ ์ฌ์ฉํด idempotent upsert๋ฅผ ๊ตฌํํฉ๋๋ค.
- retries, ์ค๋ณต ๋ฉ์์ง, ์๊ตฌ ์คํจ๋ฅผ ์ง๋จํ ์ ์์ ๋งํผ ์ถฉ๋ถํ logs๋ฅผ ๊ธฐ๋กํฉ๋๋ค.
์ด๋ฒคํธ ๊ธฐ๋ฐ ๋๊ธฐํ
์ ์ฒด ํ๋ฆ์ domain, application, Unit of Work, Outbox, worker, bus, consumer๋ฅผ ๊ฒฐํฉํฉ๋๋ค. ๋ชฉํ๋ ๋ชจ๋์ด๋ ์๋น์ค ๊ฐ์ ์ทจ์ฝํ ์ง์ ํธ์ถ์ ํผํ๊ณ , ๊ฒ์ ๋๋ ์๋น๊ฐ ์คํจํ์ ๋ retry, audit, reprocessing์ ๊ฐ๋ฅํ๊ฒ ํ๋ ๊ฒ์ ๋๋ค.
- aggregate๊ฐ ๋ณ๊ฒฝ๋๊ณ domain event๋ฅผ ๋ฑ๋กํฉ๋๋ค.
- Unit of Work๊ฐ transaction ์์์ ๋ณ๊ฒฝ์ ์ ์ฅํฉ๋๋ค.
- domain handler๊ฐ ๊ทธ ์ฌ์ค์ ๋ฐ์ํ์ฌ integration event๋ฅผ
IOutbox์ ๋ฑ๋กํฉ๋๋ค. - Unit of Work๊ฐ business data์
OutboxMessage๋ฅผ ๊ฐ์ transaction์ ์ ์ฅํฉ๋๋ค. - Hangfire worker๊ฐ Outbox๋ฅผ ์ฝ๊ณ MassTransit/RabbitMQ๋ฅผ ํตํด bus์ ๊ฒ์ํฉ๋๋ค.
- consumer๊ฐ
IIntegrationEventHandler๋ฅผ ํตํด ๋ฉ์์ง๋ฅผ ๋ฐ์ต๋๋ค. - consumer๋ local model, shadow entity, projection, email, external integration ๋๋ ๋ค๋ฅธ asynchronous flow๋ฅผ ๊ฐฑ์ ํฉ๋๋ค.
Domain change -> Domain Event -> Domain Handler -> Integration Event -> Outbox -> Worker -> Event Bus -> Consumer -> Local model
์ค๊ณ ๊ท์น
- invariants๋ domain์ ๋ก๋๋ค. events๋ ํ์ ๊ท์น์ ์จ๊ธฐ๊ธฐ ์ํด์๊ฐ ์๋๋ผ reactions๋ฅผ ์ํด ์ฌ์ฉํฉ๋๋ค.
- integration events๋ business change์ ๊ฐ์ transaction ์์์ ๋ฑ๋กํฉ๋๋ค.
- integration contracts๋ ์๊ณ , versionableํ๋ฉฐ, ์์ ์ ์ผ๋ก ์ ์งํฉ๋๋ค.
- retries์ ์ค๋ณต ๋ฉ์์ง๊ฐ ๋ฐ์ํ ์ ์์ผ๋ฏ๋ก idempotent consumers๋ฅผ ๊ตฌํํฉ๋๋ค.
- worker failures์ Outbox์ ๋ฉ์ถ messages๋ฅผ ๋ชจ๋ํฐ๋งํฉ๋๋ค.
์ค์ง์ ์ธ ๊ฒฐ๊ณผ: producer๋ consumers๋ฅผ ์ ํ์๊ฐ ์๊ณ , consumers๋ producer ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ ๊ทผํ์ง ์์ผ๋ฉฐ, broker๋ consumer๊ฐ ์ผ์์ ์ผ๋ก ์ฌ์ฉํ ์ ์์ด๋ context ๊ฐ ํต์ ์ resilientํ๊ฒ ์ ์ง๋ฉ๋๋ค.
