Raiffeisenbank .NET ๊ฐ๋ฐ์ ์ปค๋ฎค๋ํฐ์์๋ ViennaNET์ ์ฝํ
์ธ ๋ฅผ ๊ณ์ํด์ ๊ฐ๋ตํ๊ฒ ๊ฒํ ํ๊ณ ์์ต๋๋ค. ์ฐ๋ฆฌ๊ฐ ์ฌ๊ธฐ๊น์ง ์จ ๋ฐฉ๋ฒ๊ณผ ์ด์ ์ ๋ํด,
์ด ๊ธฐ์ฌ์์๋ GitHub ์ ์ฅ์(
๋น์๋NET.์ฌ๊ฐ
ํ๋ก์ ํธ๊ฐ DDD ๋ฐ ๋ง์ดํฌ๋ก์๋น์ค ์ํคํ
์ฒ๋ก ์ ํ๋๋ฉด ๋น์ฆ๋์ค ๋
ผ๋ฆฌ๊ฐ ์ฌ๋ฌ ์๋น์ค์ ๋ถ์ฐ๋๋ฉด ๋ถ์ฐ ํธ๋์ญ์
๋ฉ์ปค๋์ฆ์ ๊ตฌํํด์ผ ํ๋ ๊ฒ๊ณผ ๊ด๋ จ๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํฉ๋๋ค. ๋ง์ ์๋๋ฆฌ์ค๊ฐ ๋์์ ์ฌ๋ฌ ๋๋ฉ์ธ์ ์ํฅ์ ๋ฏธ์น๋ ๊ฒฝ์ฐ๊ฐ ๋ง๊ธฐ ๋๋ฌธ์
๋๋ค. ์๋ฅผ ๋ค์ด ์ด๋ฌํ ๋ฉ์ปค๋์ฆ์ ๋ํด ๋ ์์ธํ ์์๋ณผ ์ ์์ต๋๋ค.
์ฐ๋ฆฌ ํ๋ก์ ํธ์์๋ ๊ฐ๋จํ์ง๋ง ์ ์ฉํ ๋ฉ์ปค๋์ฆ, ์ฆ ์ค์ผ์คํธ๋ ์ด์ ๊ธฐ๋ฐ ์ฌ๊ฐ๋ฅผ ๊ตฌํํ์ต๋๋ค. ๊ทธ ๋ณธ์ง์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค. ๋ค์ํ ์๋น์ค์์ ์์ ์ ์์ฐจ์ ์ผ๋ก ์ํํด์ผ ํ๋ ํน์ ๋น์ฆ๋์ค ์๋๋ฆฌ์ค๊ฐ ์์ผ๋ฉฐ, ์ด๋ค ๋จ๊ณ์์ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ฉด ๋ชจ๋ ์ด์ ๋จ๊ณ์ ๋ํด ๋กค๋ฐฑ ์ ์ฐจ๋ฅผ ํธ์ถํด์ผ ํฉ๋๋ค. ์ ๊ณต๋ฉ๋๋ค. ๋ฐ๋ผ์ ์ด์ผ๊ธฐ๊ฐ ๋๋๋ฉด ์ฑ๊ณต ์ฌ๋ถ์ ๊ด๊ณ์์ด ๋ชจ๋ ์์ญ์์ ์ผ๊ด๋ ๋ฐ์ดํฐ๋ฅผ ๋ฐ๊ฒ ๋ฉ๋๋ค.
์ฐ๋ฆฌ์ ๊ตฌํ์ ์ฌ์ ํ โโ๊ธฐ๋ณธ ํํ๋ก ์ด๋ฃจ์ด์ง๋ฉฐ ๋ค๋ฅธ ์๋น์ค์์ ์ํธ ์์ฉ ๋ฐฉ๋ฒ ์ฌ์ฉ๊ณผ ์ฐ๊ฒฐ๋์ง ์์ต๋๋ค. ์ฌ์ฉํ๋ ๊ฒ์ ์ด๋ ต์ง ์์ต๋๋ค. ๊ธฐ๋ณธ ์ถ์ ํด๋์ค SagaBase<T>์ ์์์ ๋ง๋์ธ์. ์ฌ๊ธฐ์ T๋ ์ฌ๊ฐ๊ฐ ์๋ํ๋ ๋ฐ ํ์ํ ์ด๊ธฐ ๋ฐ์ดํฐ์ ์ผ๋ถ ์ค๊ฐ ๊ฒฐ๊ณผ๋ฅผ ์ ์ฅํ ์ ์๋ ์ปจํ ์คํธ ํด๋์ค์ ๋๋ค. ์ปจํ ์คํธ ์ธ์คํด์ค๋ ์คํ ์ค์ ๋ชจ๋ ๋จ๊ณ์ ์ ๋ฌ๋ฉ๋๋ค. Saga ์์ฒด๋ ์ํ ๋น์ ์ฅ ํด๋์ค์ด๋ฏ๋ก ์ธ์คํด์ค๋ฅผ DI์ ์ฑ๊ธํค์ผ๋ก ๋ฐฐ์นํ์ฌ ํ์ํ ์ข ์์ฑ์ ์ป์ ์ ์์ต๋๋ค.
๊ด๊ณ ์์:
public class ExampleSaga : SagaBase<ExampleContext>
{
public ExampleSaga()
{
Step("Step 1")
.WithAction(c => ...)
.WithCompensation(c => ...);
AsyncStep("Step 2")
.WithAction(async c => ...);
}
}
ํธ์ถ ์์:
var saga = new ExampleSaga();
var context = new ExampleContext();
await saga.Execute(context);
๋ค์ํ ๊ตฌํ์ ์ ์ฒด ์๋ฅผ ๋ณผ ์ ์์ต๋๋ค.
ViennaNET.Orm.*
Nhibernate๋ฅผ ํตํด ๋ค์ํ ๋ฐ์ดํฐ๋ฒ ์ด์ค๋ก ์์ ํ๊ธฐ ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ธํธ์ ๋๋ค. ์ฐ๋ฆฌ๋ Liquibase๋ฅผ ์ฌ์ฉํ์ฌ DB-First ์ ๊ทผ ๋ฐฉ์์ ์ฌ์ฉํ๋ฏ๋ก ๊ธฐ์ฑ ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ๋ฐ์ดํฐ๋ก ์์ ํ๋ ๊ธฐ๋ฅ๋ง ์์ต๋๋ค.
ViennaNET.Orm.Seedwork ะธ ViennaNET.Orm
โ ๊ธฐ๋ณธ ์ธํฐํ์ด์ค์ ๊ทธ ๊ตฌํ์ ๊ฐ๊ฐ ํฌํจํ๋ ์ฃผ์ ์ด์
๋ธ๋ฆฌ. ๊ทธ ๋ด์ฉ์ ์ข ๋ ์์ธํ ์ดํด๋ณด์.
์ธํฐํ์ด์ค IEntityFactoryService
๊ทธ๋ฆฌ๊ณ ๊ทธ ๊ตฌํ EntityFactoryService
์์
๋จ์, ํน์ ์ํฐํฐ ์์
์ ์ํ ๋ฆฌํฌ์งํ ๋ฆฌ, ๋ช
๋ น ์คํ์ ๋ฐ ์ง์ SQL ์ฟผ๋ฆฌ๊ฐ ์ฌ๊ธฐ์์ ์์ฑ๋๋ฏ๋ก ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์
์ ์ฃผ์ ์์์ ์ด ๋ฉ๋๋ค. ์๋ฅผ ๋ค์ด ๋ฐ์ดํฐ๋ฅผ ์ฝ๋ ๊ธฐ๋ฅ๋ง ์ ๊ณตํ๋ ๋ฑ ๋ฐ์ดํฐ๋ฒ ์ด์ค ์์
์ ์ํด ํด๋์ค์ ๊ธฐ๋ฅ์ ์ ํํ๋ ๊ฒ์ด ํธ๋ฆฌํ ๊ฒฝ์ฐ๋ ์์ต๋๋ค. ๊ทธ๋ฌํ ๊ฒฝ์ฐ IEntityFactoryService
์กฐ์์ด ์์ต๋๋ค - ์ธํฐํ์ด์ค IEntityRepositoryFactory
, ๋ฆฌํฌ์งํ ๋ฆฌ ์์ฑ ๋ฐฉ๋ฒ๋ง ์ ์ธํฉ๋๋ค.
๋ฐ์ดํฐ๋ฒ ์ด์ค์ ์ง์ ์ก์ธ์คํ๊ธฐ ์ํด ๊ณต๊ธ์ ๋ฉ์ปค๋์ฆ์ด ์ฌ์ฉ๋ฉ๋๋ค. ์ฐ๋ฆฌ ํ์์ ์ฌ์ฉํ๋ ๊ฐ DBMS์๋ ์์ฒด ๊ตฌํ์ด ์์ต๋๋ค. ViennaNET.Orm.MSSQL, ViennaNET.Orm.Oracle, ViennaNET.Orm.SQLite, ViennaNET.Orm.PostgreSql
.
๋์์ ์ฌ๋ฌ ๊ณต๊ธ์๋ฅผ ํ๋์ ์ ํ๋ฆฌ์ผ์ด์ ์ ๋์์ ๋ฑ๋กํ ์ ์์ต๋๋ค. ์ด๋ฅผ ํตํด ์๋ฅผ ๋ค์ด ํ๋์ ์๋น์ค ํ๋ ์์ํฌ ๋ด์์ ์ธํ๋ผ ์์ ๋น์ฉ ์์ด ๋จ๊ณ๋ณ ๋ง์ด๊ทธ๋ ์ด์ ์ ์ํํ ์ ์์ต๋๋ค. ํ๋์ DBMS์์ ๋ค๋ฅธ DBMS๋ก. ํ์ํ ์ฐ๊ฒฐ์ ์ ํํ๊ณ ๋ฐ๋ผ์ ํน์ ์ํฐํฐ ํด๋์ค(๋ฐ์ดํฐ๋ฒ ์ด์ค ํ ์ด๋ธ์ ๋ํ ๋งคํ์ด ์์ฑ๋จ)์ ๋ํ ๊ณต๊ธ์๋ฅผ ์ ํํ๋ ๋ฉ์ปค๋์ฆ์ BoundedContext ํด๋์ค(๋๋ฉ์ธ ์ํฐํฐ ๋ฑ๋ก์ ์ํ ๋ฉ์๋ ํฌํจ) ๋๋ ๊ทธ ํ์ ํญ๋ชฉ์ ์ํฐํฐ๋ฅผ ๋ฑ๋กํ์ฌ ๊ตฌํ๋ฉ๋๋ค. ApplicationContext(์ ํ๋ฆฌ์ผ์ด์ ์ํฐํฐ, ์ง์ ์์ฒญ ๋ฐ ๋ช ๋ น์ ๋ฑ๋กํ๊ธฐ ์ํ ๋ฉ์๋ ํฌํจ), ๊ตฌ์ฑ์ ์ฐ๊ฒฐ ์๋ณ์๊ฐ ์ธ์๋ก ํ์ฉ๋ฉ๋๋ค.
"db": [
{
"nick": "mssql_connection",
"dbServerType": "MSSQL",
"ConnectionString": "...",
"useCallContext": true
},
{
"nick": "oracle_connection",
"dbServerType": "Oracle",
"ConnectionString": "..."
}
],
์์ ์ ํ๋ฆฌ์ผ์ด์ ์ปจํ ์คํธ:
internal sealed class DbContext : ApplicationContext
{
public DbContext()
{
AddEntity<SomeEntity>("mssql_connection");
AddEntity<MigratedSomeEntity>("oracle_connection");
AddEntity<AnotherEntity>("oracle_connection");
}
}
์ฐ๊ฒฐ ID๋ฅผ ์ง์ ํ์ง ์์ผ๋ฉด "default"๋ผ๋ ์ฐ๊ฒฐ์ด ์ฌ์ฉ๋ฉ๋๋ค.
๋ฐ์ดํฐ๋ฒ ์ด์ค ํ
์ด๋ธ์ ๋ํ ์ํฐํฐ์ ์ง์ ๋งคํ์ ํ์ค NHibernate ๋๊ตฌ๋ฅผ ์ฌ์ฉํ์ฌ ๊ตฌํ๋ฉ๋๋ค. XML ํ์ผ๊ณผ ํด๋์ค๋ฅผ ํตํด ์ค๋ช
์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ๋จ์ ํ
์คํธ์์ ์คํ
์ ์ฅ์๋ฅผ ํธ๋ฆฌํ๊ฒ ์์ฑํ๊ธฐ ์ํด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๊ฐ ์์ต๋๋ค. ViennaNET.TestUtils.Orm
.
ViennaNET.Orm.* ์ฌ์ฉ์ ์ ์ฒด ์๋ฅผ ์ฐพ์ ์ ์์ต๋๋ค.
ViennaNET.Messaging.*
๋๊ธฐ์ด ์์ ์ ์ํ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ธํธ์ ๋๋ค.
ํ ์์
์ ์ํด ๋ค์ํ DBMS์ ๋์ผํ ์ ๊ทผ ๋ฐฉ์, ์ฆ ์ฌ์ฉ๋ ํ ๊ด๋ฆฌ์์ ๊ด๊ณ์์ด ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์์
์ธก๋ฉด์์ ๊ฐ๋ฅํ ์ต๋ ํตํฉ ์ ๊ทผ ๋ฐฉ์์ด ์ ํ๋์์ต๋๋ค. ๋์๊ด ViennaNET.Messaging
์ด๋ฒ ํต์ผ์ ์ฑ
์์ ๋ฐ๋ก ๊ทธ๋ถ์๊ฒ ์์ผ๋ฉฐ, ViennaNET.Messaging.MQSeriesQueue, ViennaNET.Messaging.RabbitMQQueue ะธ ViennaNET.Messaging.KafkaQueue
๊ฐ๊ฐ IBM MQ, RabbitMQ ๋ฐ Kafka์ ๋ํ ์ด๋ํฐ ๊ตฌํ์ ํฌํจํฉ๋๋ค.
๋๊ธฐ์ด ์์ ์๋ ๋ฉ์์ง ์์ ๊ณผ ์ ์ก์ด๋ผ๋ ๋ ๊ฐ์ง ํ๋ก์ธ์ค๊ฐ ์์ต๋๋ค.
๋ฐ๋ ๊ฒ์ ๊ณ ๋ คํด ๋ณด์ธ์. ์ฌ๊ธฐ์๋ ์ฐ์ ์ฒญ์ทจ์ ๋จ์ผ ๋ฉ์์ง ์์ ์ด๋ผ๋ ๋ ๊ฐ์ง ์ต์
์ด ์์ต๋๋ค. ํ๋ฅผ ์ง์์ ์ผ๋ก ์์ ํ๋ ค๋ฉด ๋จผ์ ๋ค์์์ ์์๋ ํ๋ก์ธ์ ํด๋์ค๋ฅผ ์ค๋ช
ํด์ผ ํฉ๋๋ค. IMessageProcessor
, ์์ ๋ฉ์์ง ์ฒ๋ฆฌ๋ฅผ ๋ด๋นํฉ๋๋ค. ๋ค์์ผ๋ก ํน์ ๋๊ธฐ์ด์ "์ฐ๊ฒฐ"๋์ด์ผ ํฉ๋๋ค. ์ด๋ ๋ฑ๋ก์ ํตํด ์ํ๋ฉ๋๋ค. IQueueReactorFactory
๊ตฌ์ฑ์์ ๋๊ธฐ์ด ์๋ณ์๋ฅผ ๋ํ๋
๋๋ค.
"messaging": {
"ApplicationName": "MyApplication"
},
"rabbitmq": {
"queues": [
{
"id": "myQueue",
"queuename": "lalala",
...
}
]
},
๋ฃ๊ธฐ ์์์ ์:
_queueReactorFactory.Register<MyMessageProcessor>("myQueue");
var queueReactor = queueReactorFactory.CreateQueueReactor("myQueue");
queueReactor.StartProcessing();
๊ทธ๋ฐ ๋ค์ ์๋น์ค๊ฐ ์์๋๊ณ ์์ ๋๊ธฐ๋ฅผ ์์ํ๊ธฐ ์ํด ๋ฉ์๋๊ฐ ํธ์ถ๋๋ฉด ์ง์ ๋ ๋๊ธฐ์ด์ ๋ชจ๋ ๋ฉ์์ง๊ฐ ํด๋น ํ๋ก์ธ์๋ก ์ด๋ํฉ๋๋ค.
ํฉํ ๋ฆฌ ์ธํฐํ์ด์ค์์ ๋จ์ผ ๋ฉ์์ง๋ฅผ ๋ฐ์ผ๋ ค๋ฉด IMessagingComponentFactory
๋ฐฉ๋ฒ์ด ์์ต๋๋ค CreateMessageReceiver
๊ทธ๋ฌ๋ฉด ์ง์ ๋ ๋๊ธฐ์ด์์ ๋ฉ์์ง๋ฅผ ๊ธฐ๋ค๋ฆฌ๋ ์์ ์๊ฐ ์์ฑ๋ฉ๋๋ค.
using (var receiver = _messagingComponentFactory.CreateMessageReceiver<TestMessage>("myQueue"))
{
var message = receiver.Receive();
}
๋ฉ์์ง๋ฅผ ๋ณด๋ด๋ ค๋ฉด ๋น์ ์ ๊ฐ์ ๊ฒ์ ์ฌ์ฉํด์ผํฉ๋๋ค IMessagingComponentFactory
๋ฉ์์ง ๋ฐ์ ์๋ฅผ ๋ง๋ญ๋๋ค.
using (var sender = _messagingComponentFactory.CreateMessageSender<MyMessage>("myQueue"))
{
sender.SendMessage(new MyMessage { Value = ...});
}
๋ฉ์์ง ์ง๋ ฌํ ๋ฐ ์ญ์ง๋ ฌํ๋ฅผ ์ํ ์ธ ๊ฐ์ง ๊ธฐ์ฑ ์ต์
์ด ์์ต๋๋ค. ํ
์คํธ, XML, JSON๋ฟ์ด์ง๋ง ํ์ํ ๊ฒฝ์ฐ ๊ณ ์ ํ ์ธํฐํ์ด์ค ๊ตฌํ์ ์ฝ๊ฒ ๋ง๋ค ์ ์์ต๋๋ค. IMessageSerializer ะธ IMessageDeserializer
.
์ฐ๋ฆฌ๋ ๊ฐ ํ ๊ด๋ฆฌ์์ ๊ณ ์ ํ ๊ธฐ๋ฅ์ ๋ณด์กดํ๋ ค๊ณ ๋
ธ๋ ฅํ์ต๋๋ค. ViennaNET.Messaging.MQSeriesQueue
ํ
์คํธ๋ฟ๋ง ์๋๋ผ ๋ฐ์ดํธ ๋ฉ์์ง๋ ๋ณด๋ผ ์ ์์ต๋๋ค. ViennaNET.Messaging.RabbitMQQueue
๋ผ์ฐํ
๋ฐ ์ฆ์ ๋๊ธฐ์ด์ ์ง์ํฉ๋๋ค. RabbitMQ์ฉ ์ด๋ํฐ ๋ํผ๋ RPC์ ์ ์ฌํ๊ฒ ๊ตฌํํฉ๋๋ค. ์ฆ, ๋ฉ์์ง๋ฅผ ๋ณด๋ด๊ณ ํ๋์ ์๋ต ๋ฉ์์ง์ ๋ํด์๋ง ์์ฑ๋๋ ํน์ ์์ ๋๊ธฐ์ด์ ์๋ต์ ๊ธฐ๋ค๋ฆฝ๋๋ค.
์ฌ๊ธฐ์
ViennaNET.CallContext
์ฐ๋ฆฌ๋ ์๋ก ๋ค๋ฅธ ์์คํ
๊ฐ์ ํตํฉ๋ฟ๋ง ์๋๋ผ ๋์ผํ ์ ํ๋ฆฌ์ผ์ด์
์ ๋ง์ดํฌ๋ก์๋น์ค ๊ฐ ํต์ (์: ์ฌ๊ฐ ๋ด)์๋ ๋๊ธฐ์ด์ ์ฌ์ฉํฉ๋๋ค. ์ด๋ก ์ธํด ์ฌ์ฉ์ ๋ก๊ทธ์ธ, ์ข
๋จ ๊ฐ ๋ก๊น
์ ์ํ ์์ฒญ ์๋ณ์, ์์ค IP ์ฃผ์ ๋ฐ ์ธ์ฆ ๋ฐ์ดํฐ์ ๊ฐ์ ๋ณด์กฐ ๋ฐ์ดํฐ๋ฅผ ๋ฉ์์ง์ ํจ๊ป ์ ์กํด์ผ ํ์ต๋๋ค. ์ด ๋ฐ์ดํฐ ์ ๋ฌ์ ๊ตฌํํ๊ธฐ ์ํด ์ฐ๋ฆฌ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ๊ฐ๋ฐํ์ต๋๋ค. ViennaNET.CallContext
, ์๋น์ค์ ์
๋ ฅ๋๋ ์์ฒญ์ ๋ฐ์ดํฐ๋ฅผ ์ ์ฅํ ์ ์์ต๋๋ค. ์ด ๊ฒฝ์ฐ ๋๊ธฐ์ด์ด๋ Http๋ฅผ ํตํด ์์ฒญ์ด ์ด๋ฃจ์ด์ง ๋ฐฉ์์ ์ค์ํ์ง ์์ต๋๋ค. ๊ทธ๋ฐ ๋ค์ ๋๊ฐ๋ ์์ฒญ์ด๋ ๋ฉ์์ง๋ฅผ ๋ณด๋ด๊ธฐ ์ ์ ์ปจํ
์คํธ์์ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ ธ์ ํค๋์ ๋ฐฐ์นํฉ๋๋ค. ๋ฐ๋ผ์ ๋ค์ ์๋น์ค์์๋ ๊ฐ์ ๋ฐฉ๋ฒ์ผ๋ก ๋ณด์กฐ๋ฐ์ดํฐ๋ฅผ ๋ฐ์ ๊ด๋ฆฌํ๊ฒ ๋๋ค.
๊ด์ฌ์ ๊ฐ์ ธ์ฃผ์
์ ๊ฐ์ฌํฉ๋๋ค. ์ฌ๋ฌ๋ถ์ ์๊ฒฌ๊ณผ ๋์ด์ค๊ธฐ ์์ฒญ์ ๊ธฐ๋ค๋ฆฌ๊ฒ ์ต๋๋ค!
์ถ์ฒ : habr.com