DeviceAgent Task Lifecycle Detail
이 문서는 submitTask와 submitWorkflow가 실제 DeviceAgent 내부에서 어떤 순서로 처리되는지 상세히 정리한다.
앞의 문서들이 layer와 파일 위치를 설명한다면, 이 문서는 “runtime에서 한 번의 task/workflow가 어떻게 지나가는가”를 설명한다.
1. submitTask 처리 흐름
submitTask는 단일 실행 요청의 공통 admission gate다.
소스 근거:
task/TaskManager.java
submitTask(...)
createTaskCommand(...)
submitAndWait(...)
submitAsync(...)
처리 순서:
| 순서 | 단계 | 실제 코드/역할 |
|---|---|---|
| 1 | enabled check | isEnabled(indata)가 false면 taskmanager_disabled |
| 2 | method 확인 | taskMethod 누락 시 missing_task_method |
| 3 | validation | TaskBundleValidator.validateSubmitTask(taskMethod, indata) |
| 4 | input 복사 | copyForTask(taskMethod, indata) |
| 5 | policy 결정 | TaskPolicyRegistry.resolve(taskMethod, indata) |
| 6 | source 해석 | TaskSource.from(source) |
| 7 | caller/state/resource check | source policy, main state, battery/queue/resource 조건 확인 |
| 8 | command 생성 | createTaskCommand(taskMethod, taskInput, taskOutput, factory) |
| 9 | 실행 mode 분기 | DIRECT, QUEUED_WAIT, ASYNC |
| 10 | event 발행 | STARTED, PROGRESS, COMPLETED, FAILED, CANCELLED |
2. createTaskCommand의 의미
TaskManager가 실제 device function을 직접 전부 구현하는 구조가 아니다.
현재 command 생성은 두 단계다.
1. MainApi에서 넘긴 factory.create(method, indata, outdata)
2. 없으면 TaskExecutorRegistry.getInstance().create(method, indata, outdata)
즉 기존 MainApi.executeMethodInternal(...) 경로와 신규 executor registry 경로가 공존한다.
| 우선순위 | 경로 | 의미 |
|---|---|---|
| 1 | MainApi factory | 기존 MainApi/domain 분기를 재사용 |
| 2 | TaskExecutorRegistry | method별로 등록된 executor adapter 사용 |
이 구조 때문에 기존 domain logic을 무리하게 재작성하지 않고 TaskManager framework에 연결할 수 있다.
3. submitWorkflow 처리 흐름
submitWorkflow는 여러 subTask를 하나의 parent workflow task로 묶는다.
소스 근거:
task/TaskManager.java
submitWorkflow(...)
validateWorkflowSubTask(...)
notifyTaskEvent("WORKFLOW_STEP_STARTED", record)
notifyTaskEvent("WORKFLOW_STEP_COMPLETED", record)
처리 순서:
| 순서 | 단계 | 실제 코드/역할 |
|---|---|---|
| 1 | enabled check | TaskManager 적용 여부 확인 |
| 2 | subTasks 확인 | subTasks 없으면 missing_subtasks |
| 3 | workflow policy | ensureWorkflowPolicy(TaskPolicyRegistry.resolve(workflowName, indata)) |
| 4 | source/resource check | source policy와 resource policy 확인 |
| 5 | parent record 생성 | newTaskRecord(workflowName, workflowInput, policy, source, workflowName) |
| 6 | subTask loop | 각 subTask를 순차 처리 |
| 7 | subTask validation | TaskBundleValidator.validateWorkflowSubTask(...) |
| 8 | step state 기록 | currentStepIndex, currentStepMethod, workflowStepStates |
| 9 | step started event | WORKFLOW_STEP_STARTED |
| 10 | sub command 실행 | createTaskCommand(...) 후 subCommand.run() |
| 11 | step completed event | WORKFLOW_STEP_COMPLETED |
| 12 | 결과 기록 | subTaskResults, subTaskStates |
4. 실행 시점 조건 판단
복합명령에서 중요한 점은 “등록 시점”과 “실행 시점”을 구분하는 것이다.
예:
거실로 가서 청정하고 안방으로 이동해
이 발화가 아래 workflow가 되었다고 가정한다.
subTasks[0] = setMoveTo(position=거실)
subTasks[1] = setAirCleanerOperation(position=거실, action=on)
subTasks[2] = setMoveTo(position=안방)
이때 setAirCleanerOperation의 실제 조건은 workflow 등록 시점이 아니라 setMoveTo(거실)이 끝난 뒤 확인해야 한다.
따라서 원칙은 아래와 같다.
| 구분 | 판단 내용 |
|---|---|
| registration-time | taskMethod 존재, 필수 slot 존재, source/caller 허용 여부 |
| execution-time | 현재 위치, 이동 상태, 청정 상태, 배터리, 맵 상태, room availability |
| failure-time | 실패한 currentStepIndex, currentStepMethod, reason_code, reason_params 기록 |
5. Event 발행 위치
TaskManager event는 notifyTaskEvent(...)에서 공통 발행한다.
소스 근거:
TaskManager.notifyTaskEvent(...)
record.writeSummaryTo(eventData)
eventData.method = "onTaskEvent"
eventData.eventName = eventName
listener.onTaskEvent(...)
AppCmd.INSTANCE.sendModuleCallback_main(eventData)
중요한 점:
| Event | Cloud 판단 필요성 |
|---|---|
QUEUED, STARTED, PROGRESS, WORKFLOW_STEP_STARTED |
보통 불필요. 로컬 상태/UI/로그 갱신 |
WORKFLOW_STEP_COMPLETED, COMPLETED, WORKFLOW_COMPLETED |
보통 불필요. 다음 step 또는 완료 처리 |
FAILED, CANCELLED, PAUSED, BLOCKED |
reason_code와 requires_cloud_decision에 따라 상위 판단 후보 |
6. 업체 구현 체크포인트
| 항목 | 확인 기준 |
|---|---|
| taskMethod 누락 처리 | missing_task_method로 reject |
| subTasks 누락 처리 | missing_subtasks로 reject |
| validation 분리 | 단일 task와 workflow subTask 검증 함수를 분리 |
| policy 반영 | method별 queue/mode/timeout/retry가 registry에서 결정 |
| command fallback | factory 우선, registry fallback 구조 유지 |
| step event | subTask 시작/완료 event를 parent workflow record 기준으로 발행 |
| result 기록 | subTaskResults, subTaskStates가 outdata/result에 남음 |
| failure reason | terminal 실패 event에 표준 reason_code를 포함 |