이 페이지에서는 Handler
인터페이스의 설계를 설명하겠습니다.
서버에 제공하는 Handler
는 비동기 작업 처리 로직의 핵심입니다. Handler의 책임은 작업을 수락하고 컨텍스트를 고려하여 처리하는 것입니다. 처리가 실패하면 나중에 작업을 다시 시도하기 위해 오류를 보고해야 합니다.
이 인터페이스는 다음과 같이 정의됩니다.
type Handler interface {
ProcessTask(context.Context, *Task) error
}
이것은 Handler의 책임을 간결하게 설명하는 간단한 인터페이스입니다.
이 Handler 인터페이스를 구현하는 다양한 방법이 있습니다.
작업을 처리하기 위해 자체 구조체 유형을 정의하는 예제는 다음과 같습니다.
type MyTaskHandler struct {
// ... 필드
}
// ProcessTask 메서드 구현
func (h *MyTaskHandler) ProcessTask(ctx context.Context, t *asynq.Task) error {
// ... 작업 처리 로직
}
심지어 HandlerFunc
어댑터 유형 덕분에 인터페이스를 충족하는 함수를 정의할 수도 있습니다.
func myHandler(ctx context.Context, t *asynq.Task) error {
// ... 작업 처리 로직
}
// h는 Handler 인터페이스를 충족합니다
h := asynq.HandlerFunc(myHandler)
대부분의 경우, 입력 작업의 Type
을 확인하고 그에 따라 처리해야 할 수도 있습니다.
func (h *MyTaskHandler) ProcessTask(ctx context.Context, t *asynq.Task) error {
switch t.Type() {
case "type1":
// type1 처리
case "type2":
// type2 처리
case "typeN":
// typeN 처리
default:
return fmt.Errorf("예기치 않은 작업 유형: %q", t.Type())
}
}
Handler는 여러 다른 핸들러로 구성될 수 있습니다. 위의 예에서 각 경우는 전용 핸들러에 의해 처리될 수 있습니다. 이것이 ServeMux
유형이 필요한 이유입니다.
참고: ServeMux
유형을 사용하여 핸들러를 구현할 필요는 없지만 여러 경우에 유용할 수 있습니다.ServeMux
를 사용하면 여러 핸들러를 등록할 수 있습니다. 각 작업 유형과 등록된 패턴을 일치시키고 작업 유형 이름과 가장 가까운 패턴에 해당하는 핸들러를 호출합니다.
mux := asynq.NewServeMux()
mux.Handle("email:welcome", welcomeEmailHandler) // 핸들러 등록
mux.Handle("email:reminder", reminderEmailHandler)
mux.Handle("email:", defaultEmailHandler) // "email:"로 시작하는 다른 작업 유형에 대한 기본 핸들러
미들웨어 사용
요청을 처리하기 전/후에 일부 코드를 실행해야하는 경우 미들웨어를 사용하여 이를 달성할 수 있습니다. 미들웨어는 Handler
를 가져와 Handler
를 반환하는 함수입니다.
아래는 작업 처리의 시작과 끝을 로깅하는 미들웨어의 예제입니다.
func loggingMiddleware(h asynq.Handler) asynq.Handler {
return asynq.HandlerFunc(func(ctx context.Context, t *asynq.Task) error {
start := time.Now()
log.Printf("%q에 대한 처리가 시작되었습니다", t.Type())
err := h.ProcessTask(ctx, t)
if err != nil {
return err
}
log.Printf("%q에 대한 처리가 완료되었습니다: 경과 시간 = %v", t.Type(), time.Since(start))
return nil
})
}
이제 이 미들웨어를 사용하여 핸들러를 “래핑”할 수 있습니다.
myHandler = loggingMiddleware(myHandler)
또한 ServeMux
를 사용하는 경우 다음과 같이 미들웨어를 제공할 수 있습니다.
mux := NewServeMux()
mux.Use(loggingMiddleware)
미들웨어 그룹화
여러 작업에 미들웨어를 적용하려는 시나리오가 있는 경우, 여러 ServeMux
인스턴스를 결합하여 이를 달성할 수 있습니다. 하나의 제한 사항은 각 작업 그룹이 유형 이름의 동일한 접두사를 가져야 한다는 것입니다.
예시:
주문 처리 작업과 제품 처리 작업이 있고, “제품” 작업에 대한 모든 공유 로직을 적용하고 다른 “주문” 작업에 대한 다른 공유 로직을 적용하려는 경우, 다음과 같이 수행할 수 있습니다:
productHandlers := asynq.NewServeMux()
productHandlers.Use(productMiddleware) // 모든 제품 작업에 공유 로직 적용
productHandlers.HandleFunc("product:update", productUpdateTaskHandler)
// ... 다른 "제품" 작업 핸들러 등록
orderHandlers := asynq.NewServeMux()
orderHandler.Use(orderMiddleware) // 모든 주문 작업에 공유 로직 적용
orderHandlers.HandleFunc("order:refund", orderRefundTaskHandler)
// ... 다른 "주문" 작업 핸들러 등록
// 상위 수준 핸들러
mux := asynq.NewServeMux()
mux.Use(someGlobalMiddleware) // 모든 작업에 공유 로직 적용
mux.Handle("product:", productHandlers)
mux.Handle("order:", orderHandlers)
if err := srv.Run(mux); err != nil {
log.Fatal(err)
}