Custom API vs Custom Action vs Azure Function: Dataverse 선택
Source: Dev.to
클라이언트는 “이 고객의 충성도 리베이트를 계산한다”는 작업을 외부에 제공해야 합니다. 이 작업은 Dataverse의 세 개 테이블을 읽고, 몇 가지 비즈니스 규칙을 적용한 뒤 결과를 기록합니다. 모든 소비자—Dynamics 웹 앱, Power Automate 흐름, 외부 연동—가 동일한 작업을 호출해야 합니다.
이를 구현할 수 있는 위치는 세 군데이며, 각각 비용·지연·확장성 프로파일이 다릅니다. 아래는 새로운 작업을 만들 때마다 검토하는 매트릭스입니다.
| Dimension | Custom Action (legacy) | Custom API (modern) | Azure Function |
|---|---|---|---|
| Latency | Low (in‑process) | Low (in‑process) | Medium (cross‑service) |
| Concurrency limit | Dataverse’s | Dataverse’s | Function App’s |
| Timeout | 2 minutes | 2 minutes | 10 minutes (Consumption), 설정 가능 |
| Cost | Dataverse에 포함 | Dataverse에 포함 | 실행당 + 컴퓨팅 비용 |
| Long‑running work | No | No | Yes (durable functions) |
| External dependency calls | Limited (sandbox) | Limited (sandbox) | Full flexibility |
| OpenAPI schema | No | Yes | Manual |
| Invocable from flow | Yes | Yes (first‑class) | Yes (HTTP connector) |
| Maintenance | .NET + Workflow | .NET (preferred) | .NET |
언제 Custom Action을 선택해야 할까?
이미 기존 시스템에서 Custom Action을 사용하고 있다면 유지보수 측면에서 맞습니다. 새로운 작업을 시작할 때는 건너뛰고, 더 나은 도구와 툴링을 제공하는 Custom API를 사용하세요.
Custom API가 적합한 경우
- 로직이 주로 Dataverse 조회·쓰기인 경우
- 지연 시간이 중요하고(호출당 500 ms 이하)
- 호출자가 Microsoft 스택 내부(Flow, 다른 플러그인, Dynamics 앱)인 경우
- 작업이 2 분 이내에 완료되는 경우
Azure Function이 적합한 경우
- 외부 서비스 호출 등 지연이 불확실한 경우
- 작업이 2 분을 초과할 수 있는 경우
- 내구성·재시도·체크포인팅이 필요할 때( durable functions)
- Dataverse 샌드박스가 차단하는 파일 I/O, 소켓, 네이티브 종속성이 필요한 경우
- Dataverse와 별도 비용 청구를 원할 때
비용 측면
Custom API는 Dataverse 용량을 사용합니다. 하루에 수만 건 호출되는 고볼륨 API도 기존 Dataverse 라이선스에 포함돼 추가 호출당 비용이 없습니다.
Azure Functions(Consumption 플랜) 비용은 GB‑초당 $0.000016, 실행당 $0.20(백만 건)입니다. 128 MB 메모리로 300 ms 실행되는 일반적인 함수는 호출당 약 $0.00000006 정도이며, 월 100만 호출이면 컴퓨팅 비용 $0.25와 실행 비용 $0.20 정도로 사실상 무료에 가깝습니다.
대체로 Dataverse 중심 작업은 Custom API가, 외부 종속성이 많은 작업은 Azure Function이 비용 효율적입니다. 두 방식을 혼합해 Custom API가 Function을 호출하는 패턴은 두 비용을 모두 부담하게 되므로 피하는 것이 좋습니다.
Custom API 주의점
Custom API를 구현하는 플러그인은 “Custom API message”라는 가상의 메시지에 대해 단계(step)를 등록합니다. 디버깅은 일반 플러그인과 동일하게 플러그인 트레이스 로그를 사용합니다. 배포는 솔루션을 통해 이루어집니다. OpenAPI 스키마는 customapi 레코드 정의에서 자동 생성되는데, Dataverse와 플러그인 코드에서 파라미터 이름을 하나라도 다르게 적으면 런타임 오류가 발생하고, 솔루션 검사에서는 이를 잡아내지 못합니다.
Azure Function 주의점
Consumption 플랜에서는 콜드 스타트가 발생해 최초 호출 시 2~5 초 정도 지연될 수 있습니다. 사용자와 직접 상호작용하는 호출이라면 이는 허용할 수 없습니다. 해결 방안은
- Premium 플랜(항상 Warm, 기본 비용 상승)
- Dedicated App Service 플랜
- 비동기 호출이라면 콜드 스타트를 감수
Azure Function 인증 주의점
Azure Function에서 Dataverse에 접근하려면 인증이 필요합니다. 가장 깔끔한 방법은 Function App에 Managed Identity를 부여하고, Dataverse에 해당 Identity용 Application User를 만드는 것입니다. 앱 설정에 개인 사용자 자격증명을 넣는 방식은 보안 사고 위험이 매우 높습니다.
요구 사항: “주문이 생성될 때마다 충성도 리베이트를 계산·적용한다.”
- 읽는 테이블: Customer, OrderHistory, RebateProgram (3개)
- 쓰기: 계산된 값을 Order에 기록
- 실행 시점: 모든 주문 생성 시마다
- 예상 볼륨: 하루 2 000건, 피크 시 1분당 50건
- 지연 목표: 주문 저장 시 1초 이하
매트릭스 적용
- Latency: 서브초 수준은 콜드 스타트가 있는 Azure Function에선 힘들고, Custom API는 인‑프로세스라 적합합니다.
- External dependencies: 없음, 전부 Dataverse 내부.
- Long‑running: 없음, 500 ms 이하 예상.
- Cost: Dataverse 라이선스에 이미 포함돼 있으므로 추가 비용이 들지 않는 Custom API가 유리합니다.
결론: Custom API가 명확히 승리했습니다. 구현은 Custom API 정의에 연결된 플러그인을 만들고, 이를 Order Create post‑operation 플러그인(동기식, 저장을 차단)과 Power Automate 흐름(레트로액티브 재계산)에서 모두 호출하도록 했습니다.
이후 변화
1년 뒤, 클라이언트가 3~4 초가 소요되는 외부 세금 서비스와 연동을 원했습니다. 동일한 Custom API에 넣지는 않았습니다. 2 분 제한과 외부 서비스의 불확실성을 고려해 별도 Azure Function을 만들고, Power Automate 흐름에서 비동기로 호출했습니다. 이렇게 두 도구를 각각의 지연 프로파일에 맞게 사용하는 것이 올바른 접근입니다.
요약
- 작업이 Dataverse 내부에 머무른다면: Custom API부터 시작하세요. 지연이 낮고, ALM이 통합돼 있으며, 추가 비용이 없습니다. 필요 시 나중에 Azure Function으로 옮길 수 있습니다.
- 외부 종속성이 있거나 예측 불가능한 동작이 있다면: Azure Function을 먼저 고려하세요. 내구성 패턴과 Dataverse 샌드박스가 제공하지 못하는 10분 제한을 활용할 수 있습니다.
- 새로운 작업에 Custom Action을 사용하고 있다면: 즉시 중단하세요. Custom API는 Custom Action이 제공하던 모든 기능에 스키마와 향상된 툴링을 더합니다.