1. Redis 역할 두 가지
- 실행 요청 큐 (exec Q)
- 타입: List / Stream 등 워크 큐용
- 예:
LPUSH exec_queue ..., 워커는 BRPOP exec_queue로 소비
- 역할: 해당 job 실행 요청을 worker에게 맡기는 큐
- 콜백 채널 (job_completed pub/sub)
- 타입: pub/sub channel
- 예:
PUBLISH job_completed '{"job_id": "...", "status": ...}'
- 역할: 해당 job 종료 여부를 API 서버한테 브로드캐스트하는 채널
2. 최종 구조
공통 전제
- exec Q: Redis List/Stream
- callback channel: Redis pub/sub 채널 (예:
job_completed)
- DB: Job 상태 + 결과 저장
flowchart LR
subgraph whole arcitecture
subgraph ClientSide["Client Side"]
C["Client<br>사용자 / 다른 서비스"]
end
subgraph APIServer["API Server (FastAPI)"]
A["Invoke API<br>POST /functions/{id}/invoke"]
J["Jobs API<br>GET /jobs/{jobId}"]
L["Redis Listener<br>(SUBSCRIBE job_completed)"]
WMap["waiters[jobId] -> Future"]
end
subgraph Redis["Redis"]
Q[("exec_queue<br>List/Stream")]
CH(("job_completed<br>pub/sub channel"))
end
subgraph WorkerSide["Worker"]
W["Exec Worker<br>consume exec_queue"]
end
subgraph Runtime["Function Runtime"]
R["General Runner<br>(KNative Serving)"]
end
subgraph DB
D[("Jobs DB")]
end
C -- sync/async invoke --> A
C -- GET result --> J
A -- push job --> Q
W -- BRPOP / XREAD --> Q
W -- execute --> R
R -- result --> W
W -- update status/result --> D
W -- publish job_completed --> CH
L -- receive events --> CH
L -- resolve Future --> WMap
J -- read job --> D
A -- create job (PENDING) --> D
A -- wait via Future --> WMap
end
Async 호출 플로우
POST /functions/{id}/invoke
- Job 생성(DB:
PENDING)
exec_queue 에 {job_id, function_id, payload} 넣기
- 클라이언트에
202 Accepted + jobId 반환
- Worker
exec_queue에서 job 꺼냄
- KNative Serving / Eventing / whatever으로 함수 실행
- 끝나면:
- DB에
SUCCESS/FAILED + result 저장
- (Optional )
PUBLISH job_completed '{ job_id, status, ... }'
- 클라이언트
- 알아서
GET /jobs/{jobId} 로 조회
sequenceDiagram
autonumber
participant C as Client
participant A as API Server<br/>(FastAPI)
participant D as Jobs DB
participant Q as Redis exec_queue
participant W as Exec Worker
participant R as General Runner<br/>(KNative)
participant CH as Redis job_completed
C->>A: POST /functions/{id}/invoke
A->>D: INSERT Job(PENDING, mode=async)
A->>Q: LPUSH exec_queue {jobId, functionId, payload}
A-->>C: 202 Accepted<br/>{ jobId }
loop Worker consumes exec_queue
W->>Q: BRPOP exec_queue
Q-->>W: {jobId, functionId, payload}
W->>D: UPDATE Job RUNNING
W->>R: HTTP POST /run {payload}
R-->>W: {result or error}
alt success
W->>D: UPDATE Job SUCCESS + result
W->>CH: PUBLISH job_completed {jobId, status: SUCCESS}
else failed
W->>D: UPDATE Job FAILED + error
W->>CH: PUBLISH job_completed {jobId, status: FAILED}
end
end
C->>A: GET /jobs/{jobId}
A->>D: SELECT Job
D-->>A: {status, result, error}
A-->>C: 200 OK {status, result, error}
Sync 호출 플로우 (여기서 Redis pub/sub이 중요)
POST /functions/{id}/invoke
- Job 생성(DB:
PENDING)
exec_queue에 넣기
- 메모리에
waiters[job_id] = Future 등록
- 이 Future를
await (타임아웃까지)
- Worker
- 위와 동일하게 실행 → DB 업데이트 후
PUBLISH job_completed '{ job_id, status, result_summary }'