← Docs hub

SoC TaskManager Source-Level Implementation Guide

이 장은 SoC/DeviceAgent 업체가 실제 코드 기준으로 구현을 따라 할 수 있도록 정리한 소스 레벨 가이드다. 발표용 개념 설명은 Before/After Change Model을 보고, 실제 구현 위치와 method 단위 작업은 이 문서를 기준으로 본다.

SoC TaskManager Source Level Implementation Guide

1. 핵심 결론

TaskManager는 기존 domain 동작을 대체하는 별도 앱이 아니다. 기존 MainApi.executeMethod(...) 앞단에 공통 실행 layer를 넣고, 실제 기기 동작은 기존 executeMethodInternal(...) 또는 domain executor로 위임하는 구조다.

현재 코드에서 이 구조는 아래처럼 연결되어 있다.

MainApi.executeMethod(...)
-> TaskManager.handleControlMethod(...)
-> handled이면 TaskManager API 처리 후 return
-> 아니면 TaskManager.executeLegacy(...)
-> executeMethodInternal(...)로 기존 domain 기능 실행

근거:

apps/DeviceAgent/app/src/main/java/com/sk/airbot/deviceagent/main/api/MainApi.java
  import com.sk.airbot.deviceagent.task.TaskManager;
  executeMethod(...)에서 TaskManager.handleControlMethod(...)를 먼저 호출
  처리되지 않은 method는 executeLegacy(...)를 통해 executeMethodInternal(...)로 위임

2. 기존 진입점에 추가되는 Hook

기존 구조:

DeviceAgent
-> MainApi.executeMethod(method, indata, outdata)
-> executeMethodInternal(method, indata, outdata)
-> FrameworkCommandBridge 또는 기존 switch/handler

변경 구조:

DeviceAgent
-> MainApi.executeMethod(method, indata, outdata)
-> TaskManager.handleControlMethod(method, indata, outdata, factory)
   -> submitTask / submitWorkflow / getTaskStatus / cancelTask 등 TaskManager API면 여기서 처리
-> TaskManager.executeLegacy(...)
   -> 기존 executeMethodInternal(...) 호출 유지

업체 구현 포인트:

항목 구현 내용
Hook 위치 MainApi.executeMethod(...) 맨 앞에서 TaskManager control method를 먼저 검사
기존 동작 보존 TaskManager가 처리하지 않는 method는 기존 executeMethodInternal(...)로 그대로 흘려보냄
factory 위임 TaskManager가 실제 command 실행이 필요할 때 기존 method를 호출할 수 있도록 TaskCommandFactory를 넘김
안전성 TaskManager disable 시 기존 legacy 실행이 가능한 경로를 유지

3. TaskManager API Entry

TaskManager.java는 아래 control method를 공통 API로 제공해야 한다.

submitTask
submitWorkflow
getTaskStatus
listTasks
getQueueStatus
updateTaskProgress
cancelTask
getTaskManagerStatus
getDevicePlanningContext
classifyTaskIngress

현재 코드 기준 책임:

영역 코드 책임
API dispatch handleControlMethod(...)가 method별 처리 함수로 분기
record 저장 records, recordOrder, TaskRecord로 task lifecycle 추적
queue 관리 executors, queueMetrics, PriorityTaskExecutor로 queue 상태 관리
event listener eventListeners로 내부 listener 통지
외부 callback notifyTaskEvent(...)에서 AppCmd.INSTANCE.sendModuleCallback_main(eventData) 호출

3.1 Control Method별 입력/출력

method 필수 입력 주요 출력 용도
submitTask taskMethod, source accepted, taskId, taskState, executionMode 단일 task 등록
submitWorkflow workflowName, subTasks, source accepted, taskId, workflowName, subTaskStates 복합명령 등록
getTaskStatus taskId task detail, input/result/reason 특정 task 조회
listTasks optional filter task summary list task 목록 조회
getQueueStatus 없음 또는 queue filter queue별 running/pending/state queue 상태 확인
updateTaskProgress taskId, progress/stage/message updated status 외부 executor 진행률 반영
cancelTask taskId 또는 workflow id cancel accepted/result 실행 중 task 취소
getTaskManagerStatus 없음 enabled, queue size, metrics manager 상태 조회
getDevicePlanningContext 없음 device context bundle 실행 전 planner/server context
classifyTaskIngress method, optional signalType signal type, action method 성격 분류

3.2 공통 Bundle Key 규칙

계열 key
source source, origin, caller
external trace external_command_id, externalCommandId
MQTT trace mqtt_message_id, mqttMessageId
App trace app_request_id, appRequestId
Schedule trace schedule_id, scheduleId
Cloud trace cloud_workflow_id, cloudWorkflowId, cloud_step_id, cloudStepId, cloud_plan_id, cloudPlanId
task input taskMethod, executionMode, queueKey, priority, timeoutMs, retry, cancellable, strictValidation
workflow input workflowName, subTasks, currentStepIndex, currentStepMethod
progress progress, stage, message

4. submitTask 처리 상세

submitTask는 단일 실행 요청의 공통 admission gate다.

흐름:

enabled check
-> taskMethod 필수 확인
-> TaskBundleValidator.validateSubmitTask(...)
-> copyForTask(...)
-> TaskPolicyRegistry.resolve(...)
-> TaskSource.from(source)
-> caller policy check
-> state condition check
-> resource policy check
-> createTaskCommand(...)
-> DIRECT / QUEUED_WAIT / ASYNC 실행

업체 구현 의미:

단계 의미
enabled check property 또는 bundle flag로 TaskManager 적용 여부 제어
validation method별 필수 slot 누락을 execution 전에 차단
policy resolve method별 queue, timeout, retry, cancellable, cancel method 결정
source parse Cloud/MQTT/App/예약 등 유입원을 구분
state/resource check 배터리, 이동 중, cleaning transaction, queue busy 같은 runtime 조건 반영
command creation 기존 domain handler 또는 새 executor로 실제 실행 위임

5. submitWorkflow 처리 상세

submitWorkflow는 복합명령을 위한 핵심이다. 단순히 여러 method를 한 번에 보내는 것이 아니라, workflow 자체를 task로 만들고 subTask 상태를 추적한다.

흐름:

subTasks 필수 확인
-> workflow policy 생성
-> workflow TaskRecord 생성
-> 각 subTask 순차 실행
-> parallelGroup이면 병렬 그룹 실행
-> currentStepIndex / currentStepMethod 갱신
-> WORKFLOW_STEP_STARTED event
-> subCommand.run()
-> WORKFLOW_STEP_COMPLETED event
-> subTaskResults / subTaskStates 결과 기록

예시:

submitWorkflow
  workflowName = "living_room_clean_then_bedroom_move"
  subTasks[0] = { taskMethod: "setMoveTo", positionName: "거실" }
  subTasks[1] = { taskMethod: "setAirCleanerOperation", action: 1, mode: 2 }
  subTasks[2] = { taskMethod: "setMoveTo", positionName: "안방" }

업체 구현 포인트:

항목 요구
순차 보장 앞 step이 끝나기 전 다음 step의 runtime 조건을 확정하지 않음
step event 각 step 시작/완료를 WORKFLOW_STEP_STARTED, WORKFLOW_STEP_COMPLETED로 알림
실패 처리 step 실패 시 parent workflow에 reason을 기록하고 terminal event 전송
결과 기록 subTaskResults, subTaskStates를 결과 bundle에 포함
parallelGroup 안전성 검토 후 허용 domain만 병렬 실행

5.1 Workflow에서 실행 시점 조건 판단

복합명령에서 중요한 점은 “workflow 등록 시점”과 “subTask 실행 시점”의 기기 상태가 다를 수 있다는 것이다.

예:

1. 거실로 이동
2. 거실에서 청정 시작
3. 안방으로 이동

이 경우 2번 청정 조건은 workflow 등록 시점이 아니라 1번 이동 완료 후 확인해야 한다. 따라서 업체 구현은 아래 원칙을 따른다.

원칙 설명
registration-time validation taskMethod와 필수 slot이 있는지만 확인
execution-time condition battery, map, movement, cleaning transaction, room availability는 step 실행 직전에 확인
step-local failure 실패한 step의 currentStepIndex, currentStepMethod, reason_code를 event에 남김
parent workflow terminal subTask 실패가 parent workflow terminal event로 이어져야 함

5.2 Workflow Event 순서

정상 순차 workflow:

ACCEPTED
RUNNING
WORKFLOW_STEP_STARTED(index=0)
WORKFLOW_STEP_COMPLETED(index=0)
WORKFLOW_STEP_STARTED(index=1)
WORKFLOW_STEP_COMPLETED(index=1)
WORKFLOW_STEP_STARTED(index=2)
WORKFLOW_STEP_COMPLETED(index=2)
COMPLETED or WORKFLOW_COMPLETED

실패 workflow:

ACCEPTED
RUNNING
WORKFLOW_STEP_STARTED(index=0)
WORKFLOW_STEP_COMPLETED(index=0)
WORKFLOW_STEP_STARTED(index=1)
FAILED(reason_code=PATH_BLOCKED or STATE_CONDITION_FAILED)

6. Policy Registry

TaskPolicyRegistry.java는 method별 실행 정책을 정의한다.

현재 주요 queue:

emergency
movement
cleaning
state
update
sound
settings
ai
default

대표 정책:

method mode queue timeout cancellable
getBatteryInfo DIRECT device_info 5s false
getFirmwareVersion DIRECT device_info 5s false
setMainState QUEUED_WAIT state default false
returnToStation ASYNC movement 120s true
setMoveTo ASYNC movement 120s true
setAirCleanerOperation ASYNC cleaning 60s true
setStatusClean QUEUED_WAIT cleaning default true
setChangeLlmStatus ASYNC ai default true
setConfig QUEUED_WAIT settings default false

업체 구현 포인트:

7. Bundle Validation

TaskBundleValidator.java는 strict validation이 켜졌을 때 method별 필수 입력을 검사한다.

현재 schema 예시:

method 필수 후보 key
setMoveTo positionId, positionName, position, positionIds
setMoving action, operation, moving
setAirCleanerOperation action, mode, speed, operation
setStatusClean status, cleanStatus, value
setChangeLlmStatus status, llmStatus, action
setLlmTts text, ttsText, message
setConfig key, configKey, name

주의:

8. Executor Binding

TaskExecutorBootstrap.java는 task method와 executor를 연결한다.

현재 skeleton binding:

domain methods
Movement returnToStation, setMoveTo, setMoving, stopMovement
Cleaning setAirCleanerOperation, setStatusClean, stopCleaning, ampStop
LLM/TTS setChangeLlmStatus, setLlmTts, stopLlm, stopTts
IoT setDeviceStatus, setConfig, getConfig
Update OTAUpdateArmResult, OTAUpdateMcuResult, setFirmwareUpdateStatus

업체가 해야 할 일:

  1. skeleton executor를 실제 domain manager 호출로 연결한다.
  2. dry-run executor와 real executor를 구분한다.
  3. long-running 동작은 progress update 또는 event callback을 보장한다.
  4. cancel method가 있는 domain은 stop/cancel path까지 연결한다.
  5. domain 실패를 TaskReasonContract가 이해 가능한 error code로 넘긴다.

8.1 Domain Adapter 작성 패턴

TaskManager executor는 가능하면 얇은 adapter로 유지한다.

TaskExecutor
-> input Bundle normalize
-> 기존 domain handler 호출
-> domain 결과/error를 task output 또는 exception/errorCode로 변환

청정 예시:

taskMethod = setAirCleanerOperation
-> CleaningAmpTaskExecutor
-> CleanOperationCommandHandler.handleSetAirCleanerOperation(...)
-> CleaningTransaction / PolicyGate / Executor
-> success or domain error

이동 예시:

taskMethod = setMoveTo
-> MovementTaskExecutor
-> MovingController / RobotMovementController / map location lookup
-> success, PATH_BLOCKED, ROOM_NOT_FOUND 등

금지할 구현:

9. 기존 Domain Handler와의 관계

예를 들어 setAirCleanerOperation은 기존 CleanOperationCommandHandler에서 이미 많은 조건 판단을 수행한다.

근거:

apps/DeviceAgent/app/src/main/java/com/sk/airbot/deviceagent/framework/command/CleanOperationCommandHandler.java
  handleSetAirCleanerOperation(...)
  AppCmd.INSTANCE.sendModuleCommand_iot(indata)
  Settings lock mode 확인
  InputNormalizer.normalize(...)
  PolicyGate.shouldSkipCurrentStep(...)
  PolicyGate.applyBeforeExecution(...)
  Executor.execute(...)

따라서 TaskManager가 해야 하는 일과 domain handler가 해야 하는 일을 분리해야 한다.

계층 해야 할 일 하지 말아야 할 일
TaskManager task admission, queue, workflow, event, reason, source trace 청정 세부 정책을 모두 재구현
Domain Handler 기존 기능별 조건 판단, 실제 SoC command, sensor/transaction 판단 Cloud/MQTT/App source별 workflow 상태 관리
Executor Adapter TaskManager task를 기존 handler 호출로 연결 business logic 중복 구현

10. Reason Contract

TaskReasonContract.java는 내부 error를 상위가 이해 가능한 reason으로 정규화한다.

대표 mapping:

내부 error 후보 표준 reason
TASK_TIMEOUT, TIMEOUT TIMEOUT
CANCELLED, USER_CANCELLED USER_CANCELLED
QUEUE_FULL, RESOURCE_BUSY, DEVICE_BUSY DEVICE_BUSY
CPU_LIMIT, RAM_LIMIT, THERMAL_LIMIT RESOURCE_LIMIT
BLOCKED_BY_STATE, STATE_CONDITION_FAILED STATE_CONDITION_FAILED
PATH_BLOCKED_BY_OBSTACLE, NAVIGATION_PATH_BLOCKED PATH_BLOCKED
POSITION_NOT_FOUND, LOCATION_NOT_FOUND, TARGET_NOT_FOUND ROOM_NOT_FOUND
BATTERY_LOW LOW_BATTERY
SENSOR_FAILURE SENSOR_ERROR

후처리 필드:

field 의미
reason_code 표준 실패 이유
reason_params 위치/방/대상 등 구조화 parameter
recoverability device_self_recoverable, user_action_required, auto_retryable, cloud_replan_required
suggested_action DOCK_AND_RESUME, ASK_USER_CLEAR_PATH, ASK_USER_TARGET, RETRY_OR_WAIT, REPLAN
requires_cloud_decision Cloud 판단이 필요한 실패인지 여부

중요:

11. Planning Context

DevicePlanningContextProvider.java는 실행 전 상위 planner/server가 참고할 수 있는 snapshot을 만든다.

현재 snapshot field:

schema_version = device_context.v1
snapshot_ts
updated_at_ms
main_state
battery
map
location
cleaning
movement
task_manager
capabilities

세부 내용:

bundle 주요 field
battery available, percent, is_low, is_charging, raw_capacity
map available, editable, rooms
location current_room_id, current_room_name, is_on_station
cleaning is_running, is_paused, last_action, area_info
movement moving_status, is_moving, is_paused, blocked
task_manager queue_status, busy, running_tasks, queue_summary
capabilities movement, room_cleaning, return_to_station, tts, schedule

업체 구현 포인트:

12. Ingress Classification

TaskIngressClassifier.java는 method를 task/control/progress/result/sensor/event/trigger로 분류한다.

분류 결과는 아래 용도로 쓴다.

signal type 의미 action
COMMAND_TASK 실행 command submit_task 후보
TASK_CONTROL TaskManager API task_manager_api
PROGRESS_UPDATE 진행률 update update_task_progress
RESULT_UPDATE 결과 callback update_task_result
SENSOR_DATA sensor/status 데이터 state_or_resource_update
TRIGGER schedule/alarm/trigger policy check 후 task 생성 가능
EVENT_CALLBACK callback/event event callback 처리

업체 구현 포인트:

12.1 Source별 정책 분기

source 정상 event 실패 event Cloud LLM 호출 여부
cloud_a2a On-device 상태/notification 갱신 requires_cloud_decision=true면 planner replan 후보 판단 필요 실패만
mqtt_server 서버 ack/status/report server failure report, retry, user notification 기본적으로 호출하지 않음
app_remote 앱 UI state 갱신 앱에 reason code와 조치 안내 기본적으로 호출하지 않음
local_voice 로컬 TTS/notification 사용자에게 재시도/불가 안내 필요 시만
internal_schedule 내부 log/status retry/cancel/protection policy 호출하지 않음

13. Event Payload Contract

TaskManager event는 notifyTaskEvent(...)에서 생성된다.

공통 흐름:

record.writeSummaryTo(eventData)
eventData.method = "onTaskEvent"
eventData.eventName = eventName
listener.onTaskEvent(eventName, eventData)
AppCmd.INSTANCE.sendModuleCallback_main(eventData)

event에 반드시 남겨야 할 계열:

계열 field 예시
task identity taskId, taskMethod, workflowName
state taskState, status, progress, stage, message
workflow currentStepIndex, currentStepMethod, subTaskStates
source trace source, origin, caller, external_command_id, mqtt_message_id, app_request_id, schedule_id
cloud trace cloud_workflow_id, cloud_step_id, cloud_plan_id, cloud_output_key
reason reason_code, reason_params, recoverability, suggested_action, requires_cloud_decision

14. 업체 구현 순서

권장 구현 순서:

  1. MainApi.executeMethod(...) 앞단에 TaskManager hook을 붙인다.
  2. submitTask, submitWorkflow, query/cancel/status API를 구현한다.
  3. TaskPolicyRegistry에 method별 queue/mode/timeout/cancel 정책을 채운다.
  4. TaskBundleValidator에 필수 slot schema를 채운다.
  5. TaskExecutorRegistry에 기존 domain handler adapter를 연결한다.
  6. TaskReasonContract에 domain error mapping을 추가한다.
  7. DevicePlanningContextProvider에 실제 map/location/movement/cleaning/battery 상태를 채운다.
  8. onTaskEvent payload를 Cloud/MQTT/App/예약 source별 trace와 함께 검증한다.
  9. unit/integration/instrumented/logcat evidence를 제출한다.

15. 구현 완료 기준

업체 구현은 아래가 모두 확인되어야 한다.

기준 완료 증거
API 동작 submitTask, submitWorkflow, getTaskStatus, cancelTask sample bundle
legacy 보존 TaskManager가 처리하지 않는 기존 method가 그대로 동작하는 trace
workflow step별 WORKFLOW_STEP_STARTED, WORKFLOW_STEP_COMPLETED, terminal event trace
reason 실패 case별 reason_code, reason_params, recoverability trace
source trace Cloud/MQTT/App/예약 source id가 event까지 보존되는 trace
planning context getDevicePlanningContext response sample
실기기 ADB/logcat 또는 업체 장비 trace

16. 최소 테스트 시나리오

ID 시나리오 기대 결과
T-01 submitTask(source=cloud_a2a, taskMethod=setAirCleanerOperation) accepted 후 terminal event, cloud trace 보존
T-02 submitTask(source=mqtt_server, taskMethod=setMoveTo) mqtt trace 보존, server report 가능한 event
T-03 submitWorkflow 3-step 이동/청정/이동 step event 순서와 parent terminal event
T-04 strictValidation=true에서 setMoveTo 위치 누락 rejected 또는 validation failure
T-05 이동 중 path blocked reason_code=PATH_BLOCKED, suggested_action=ASK_USER_CLEAR_PATH
T-06 low battery reason_code=LOW_BATTERY, device self recoverable
T-07 기존 legacy method 호출 TaskManager 미처리 후 기존 executeMethodInternal path 동작
T-08 getDevicePlanningContext battery/map/location/cleaning/movement/task_manager/capabilities 포함