Skip to Content

예제

io.deplite:sdk-android로 실제 자주 쓰이는 흐름을 모았어요.
모든 예제는 의존성 추가가 끝난 상태를 가정해요.

External — 트리거 호출

가장 단순한 사용. 코루틴 스코프 안에서 한 줄로 호출해요.

val deplite = Deplite(apiToken = BuildConfig.DEPLITE_API_TOKEN) lifecycleScope.launch { try { val job = deplite.triggers.run( triggerId = TRIGGER_ID, params = buildJsonObject { put("ref", "main") }, idempotencyKey = UUID.randomUUID().toString(), ) Log.i("Deplite", "${job.jobId} ${job.status}") } catch (e: DepliteApiException) { Log.e("Deplite", "${e.statusCode}: ${e.body}") } }

External — 파일 올리고 트리거

빌드 산출물(APK·tarball)을 올린 뒤, 파일 ID를 트리거 params에 실어 워크플로우에 전달하는 패턴이에요.

val uploaded = deplite.files.upload( file = File(context.cacheDir, "app.apk"), cleanupRule = CleanupRule.Ttl(3600), contentType = "application/vnd.android.package-archive", ) val job = deplite.triggers.run( triggerId = TRIGGER_ID, params = buildJsonObject { put("apkFileId", uploaded.id) put("ref", "main") }, idempotencyKey = "release-${System.currentTimeMillis()}", )

External — Sync 트리거로 결과까지 한 번에

responseMode: sync로 만들어진 트리거를 호출하면 워크플로우 완료까지 기다리고 output까지 그대로 받아요.

val job = deplite.triggers.run( triggerId = SYNC_TRIGGER_ID, params = buildJsonObject { put("ref", "v1.2.3") }, ) when { job.timedOut -> { // responseTimeoutMs 초과. 워크플로우는 백그라운드에서 계속 실행 } job.status == "success" -> { val url = job.output?.jsonObject?.get("url")?.jsonPrimitive?.content Log.i("Deplite", "Deployed: $url") } }

Embedded — Foreground Service로 Agent 운영

키오스크·전시 단말처럼 일반 앱 안에 Agent를 심는 시나리오예요.
첫 실행에서 enroll, 결과를 안전 저장소에 보관, 이후 부팅에선 그 자격으로 SSE를 구독해요.

class AgentService : Service() { private val scope = CoroutineScope(SupervisorJob() + Dispatchers.IO) override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int { startForeground(NOTIF_ID, buildNotification()) scope.launch { val (identity, privateKey, _) = SecureStore.loadAgent() val agent = DepliteAgent(identity, privateKey) // 30초 heartbeat (기본값 일치) launch { while (isActive) { runCatching { agent.heartbeat() } delay(30_000) } } // 메인 이벤트 루프 agent.events().collect { ev -> when (ev) { is AgentEvent.Deploy -> handleDeploy(agent, ev.payload) AgentEvent.SyncWorkflows -> reportWorkflows(agent) AgentEvent.Revoke -> stopSelf() AgentEvent.Ping -> {} is AgentEvent.Unknown -> Log.w("Agent", "unknown: ${ev.name}") } } } return START_STICKY } private suspend fun handleDeploy(agent: DepliteAgent, payload: DeployPayload) { try { agent.jobs.appendLogs(payload.jobId, listOf( LogItem(seq = 0, stream = LogStream.System, level = LogLevel.Info, content = "started") )) val output = executeWorkflow(payload) agent.jobs.reportResult(payload.jobId, JobResult.success(output = output)) } catch (e: Exception) { agent.jobs.reportResult(payload.jobId, JobResult.failed(exitCode = 1, errorMessage = e.message)) } } override fun onDestroy() { scope.cancel(); super.onDestroy() } }

SecureStore는 예시명이에요.
실제로는 privateKey(raw 32바이트)는 암호화 후 저장하는 것을 추천드려요.

Embedded — 워크플로우 인벤토리 동기화

SyncWorkflows 이벤트가 오면 현재 내가 실행 가능한 워크플로우 목록을 서버에 알려요.
실제 YAML 본문은 보내지 않고 이름과 메타만 보고해요.

private suspend fun reportWorkflows(agent: DepliteAgent) { agent.workflows.report(listOf( WorkflowReport(name = "deploy-prod", verboseSteps = listOf("build", "push"), secretsKeys = listOf("DB_URL")), WorkflowReport(name = "healthcheck", verboseSteps = listOf("ping")), )) }

에러 처리 — 재시도 가능한 케이스만 백오프

suspend fun <T> runWithRetry(max: Int = 3, block: suspend () -> T): T { repeat(max) { i -> try { return block() } catch (e: DepliteAuthException) { throw e // 재시도 무의미 } catch (e: DepliteApiException) { if (e.statusCode < 500 && e.statusCode != 429) throw e if (i == max - 1) throw e delay((1 shl i) * 500L) // 0.5s, 1s, 2s } } error("unreachable") } runWithRetry { deplite.triggers.run(triggerId, params = buildJsonObject {}) }

관련 문서

최종 수정 일자: