Temporal을 사용한 Go 워크플로우 애플리케이션 구현: 완전 가이드
Temporal SDK를 사용하여 Go로 워크플로우 구축하기
Temporal은 개발자가 Go와 같은 친숙한 프로그래밍 언어를 사용하여 내구성, 확장성, 결함 허용 워크플로우 애플리케이션을 구축할 수 있도록 하는 오픈 소스 엔터프라이즈급 워크플로우 엔진입니다.
복잡한 상태 전환과 재시도가 필요한 분산 애플리케이션에는 신뢰할 수 있는 오케스트레이션 프레임워크가 필요합니다.
이 가이드에서는 Temporal을 사용한 Go 워크플로우 애플리케이션 구현 방법을 설명하며, 구성, 샘플 코드, 배포 전략, 모범 사례 및 문제 해결 방법을 다룹니다.

Temporal이란 무엇이며 Go와 함께 사용하는 이유는 무엇인가
Temporal은 결함 허용, 장기간 실행되는 분산 애플리케이션 구축을 위해 설계된 워크플로우 오케스트레이션 프레임워크입니다. Temporal은 백그라운드에서 상태, 재시도, 타이머 및 장애 복구를 관리하므로 개발자는 보일러플레이트 오케스트레이션 코드 없이 애플리케이션 로직에 집중할 수 있습니다. 이는 Temporal Go SDK를 통해 Go를 비롯한 다른 언어를 지원합니다.
Temporal을 Go와 함께 사용하면 다음과 같은 장점이 있습니다.
- 워크플로우가 내구성을 가지며 재생 가능합니다.
- 액티비티 재시도 및 타임아웃이 자동으로 처리됩니다.
- 시스템 상태가 장애를 통해 유지됩니다.
- 작업 오케스트레이션 로직이 관용적인 Go 코드에 존재합니다.
핵심 개념: 워크플로우, 액티비티, 워커
첫 번째 Temporal Go 애플리케이션을 구축하기 전에 다음 핵심 개념을 이해해야 합니다.
워크플로우
워크플로우는 액티비티를 호출하는 내구성 있는 조정 로직입니다. 결정론적이어야 하며, Temporal 엔진이 이를 안정적으로 재생할 수 있어야 합니다. Go에서 워크플로우란 특별한 workflow.Context 매개변수를 가진 일반 Go 함수입니다.
액티비티
액티비티는 비결정론적 작업(I/O, 외부 API 호출)을 포함하는 작업 단위입니다. 액티비티는 워크플로우 외부에서 실행되고 결과를 워크플로우 로직으로 반환합니다.
워커
워커는 워크플로우 및 액티비티 함수를 호스팅하고 실행합니다. 워커는 Temporal 서버의 작업 큐를 폴링하고 작업을 처리합니다. 시작하기 전에 워크플로우와 액티비티를 등록해야 합니다.
작업 큐
작업 큐는 워커가 Temporal 서버에서 작업을 수신하는 방법입니다. 워크플로우와 액티비티는 사용할 작업 큐 이름을 지정합니다.
Temporal을 사용한 Go 프로젝트 설정
사전 요구 사항
- Go (1.16+)
- Temporal 서버 (로컬 또는 클라우드)
- Docker (로컬 서버용)
go.temporal.io/sdk종속성
Temporal Go SDK 설치
go get go.temporal.io/sdk
Temporal 개발 서버 시작
로컬 개발용:
docker run -d --network host temporalio/temporal-server
또는 Temporal CLI 사용:
temporal server start-dev
이 명령은 기본적으로 Temporal 서버와 Web UI를 시작합니다.
구성: 클라이언트 및 작업 큐
Temporal 클라이언트 생성
c, err := client.NewClient(client.Options{
HostPort: "localhost:7233",
})
if err != nil {
log.Fatal(err)
}
defer c.Close()
작업 큐 선택
워커용 고유한 작업 큐를 정의하세요:
const TaskQueue = "order-processing-queue"
워커와 워크플로우 시작자는 반드시 동일한 작업 큐 이름을 사용해야 합니다.
Go 예제: 워크플로우 및 액티비티
간단한 워크플로우 정의
func SampleWorkflow(ctx workflow.Context, input string) (string, error) {
ao := workflow.ActivityOptions{
TaskQueue: TaskQueue,
ScheduleToCloseTimeout: time.Minute,
}
ctx = workflow.WithActivityOptions(ctx, ao)
var result string
err := workflow.ExecuteActivity(ctx, SampleActivity, input).Get(ctx, &result)
if err != nil {
return "", err
}
return result, nil
}
액티비티 정의
func SampleActivity(ctx context.Context, message string) (string, error) {
return fmt.Sprintf("Hello %s!", message), nil
}
워커 등록 및 실행
w := worker.New(c, TaskQueue, worker.Options{})
w.RegisterWorkflow(SampleWorkflow)
w.RegisterActivity(SampleActivity)
err = w.Start()
if err != nil {
log.Fatal(err)
}
워크플로우 실행 시작
we, err := c.ExecuteWorkflow(context.Background(), client.StartWorkflowOptions{
ID: "sample-workflow-id",
TaskQueue: TaskQueue,
}, SampleWorkflow, "Developer")
Temporal 및 Go 워커 배포
프로덕션 배포 옵션
- 자체 호스팅 Temporal 클러스터: 지속적 저장소(Cassandra, MySQL)와 함께 Temporal 서비스(프론트엔드, 히스토리, 매칭) 설정.
- Temporal Cloud: SLA 및 스케일링을 갖춘 관리형 Temporal 서비스.
- Docker Compose 또는 Kubernetes: 스테이징 또는 프로덕션 환경용.
다음 사항을 구성해야 합니다:
- 지속성 계층
- 네임스페이스 설정
- TLS/보안 인증(API 키, mTLS)
워커 확장성
로드 밸런서 뒤에 여러 워커를 배포합니다. 워커는 동일한 작업 큐에 참여하여 워크로드를 공유함으로써 수평으로 확장됩니다.
Go에서 워크플로우 및 액티비티 테스트
Temporal에는 테스트 스위트가 포함되어 있습니다:
testSuite := testsuite.WorkflowTestSuite{}
env := testSuite.NewTestWorkflowEnvironment()
env.RegisterWorkflow(SampleWorkflow)
env.RegisterActivity(SampleActivity)
env.ExecuteWorkflow(SampleWorkflow, "Tester")
결과 확인:
var result string
require.NoError(t, workflowRun.Get(context.Background(), &result))
require.Equal(t, "Hello Tester!", result)
테스트 스위트를 사용한 테스트는 배포 전에 워크플로우 코드의 결정론적 특성과 신뢰성을 보장합니다. Temporal 액티비티의 기반이 되는 Go 서비스, 특히 재시도 루프, 컨텍스트 마감일 및 타이머 기반 로직을 가진 서비스에 대해서는 Testing Concurrent Go Code with testing/synctest에서 가짜 시계와 격리된 버블을 사용하여 해당 시간 의존적 동작을 격리된 상태로 단위 테스트하는 방법을 다룹니다.
프로덕션 모범 사례
- 타임아웃 및 재시도 정책: 액티비티 및 워크플로우에 합리적인 타임아웃과 재시도를 정의합니다.
- 구조화된 로깅: 추적 ID 및 상관 메타데이터와 함께 로그를 출력합니다.
- 워크플로우 ID: 추적 가능성을 위해 의미 있는 워크플로우 ID를 사용합니다.
- 자식 워크플로우 및 ContinueAsNew: 복잡한 로직을 모듈형 실행으로 분할하여 히스토리 크기를 줄입니다.
- 메트릭 및 모니터링: Prometheus 또는 기타 관찰 가능성 도구와 통합합니다.
- 액티비티에서의 신뢰할 수 있는 이벤트 발행: 액티비티가 데이터베이스에 작성하고 다른 서비스를 알림해야 할 경우, transactional outbox pattern을 사용하여 데이터베이스 커밋과 브로커 발행 사이에 이벤트가 손실되지 않도록 보장합니다.
일반적인 문제 해결
워커 폴링 안됨
- 올바른 작업 큐 이름인지 확인합니다.
- Temporal 서버로의 네트워크 연결성을 확인합니다.
워크플로우 시작 실패
- 워커 시작 전에 워크플로우 등록을 유효성 검사합니다.
- 클라이언트 연결 매개변수를 확인합니다.
액티비티 실패
- 재시도 정책 구성을 확인합니다.
- Web UI에서 오류 스택 트레이스를 검토합니다.
비결정론적 워크플로우 오류
Temporal은 결정론적 워크플로우 실행을 강제합니다. 다음 사항을 검토하세요:
math/rand사용- 워크플로우 로직 내부의 고루틴
- 워크플로우 내부의 외부 시스템 호출
항상 워크플로우가 순수한 오케스트레이션 코드이며 액티비티를 통해 외부 시스템을 호출하도록 보장해야 합니다.
Temporal in Go를 사용한 워크플로우 애플리케이션 구현을 통해 친숙한 Go 관용구를 사용하여 상태 유지, 탄력적, 확장 가능한 비즈니스 로직을 구축할 수 있습니다. Temporal의 보장된 실행 모델, 내장 재시도, 작업 큐 및 관찰 가능성 지원을 사용하면 오케스트레이션을 재발명하지 않고도 핵심 애플리케이션 로직에 집중할 수 있습니다. 간단한 워크플로우와 액티비티로 시작하여 자신 있게 복잡한 분산 오케스트레이션으로 확장하세요.
유용한 링크
- Polling Agents in AI Assistants: 11 Implementation Patterns — 스케줄러, 큐 워커, 시맨틱 폴링과 함께 Temporal과 같은 내구성 워크플로우 엔진이 프로덕션 AI 어시스턴트 백엔드에 어떻게 부합하는지
- Go Cheatsheet
- Apache Airflow for MLOPS and ETL - Description, Benefits and Examples
- Core application - Go SDK. Temporal Platform Documentation
- Temporal Go SDK samples
- Building Reliable Workflows with Temporal in Go - Essential Best Practices
- Build a Temporal Application from scratch in Go
- App Architecture hub — API design, code structure, and integration patterns