예제
deplite 패키지로 실제 자주 쓰이는 흐름을 모았어요.
모든 예제는 dart pub get이 끝난 상태를 가정해요.
External — 트리거 호출
import 'package:deplite/deplite.dart';
final deplite = Deplite(apiToken: const String.fromEnvironment('DEPLITE_API_TOKEN'));
final job = await deplite.triggers.run(
triggerId: triggerId,
params: {'ref': 'main', 'actor': 'sehyun'},
idempotencyKey: 'release-${DateTime.now().millisecondsSinceEpoch}',
);
print('${job.jobId} ${job.status}');External — 파일 올리고 트리거
import 'dart:io';
final uploaded = await deplite.files.upload(
file: File('/tmp/app.apk'),
cleanupRule: const TtlCleanup(3600),
contentType: 'application/vnd.android.package-archive',
);
final job = await deplite.triggers.run(
triggerId: triggerId,
params: {'apkFileId': uploaded.id, 'ref': 'main'},
);External — Sync 트리거로 결과까지 한 번에
responseMode: sync로 만들어진 트리거를 호출하면 워크플로우 완료까지 기다리고 output까지 그대로 받아요.
final job = await deplite.triggers.run(
triggerId: syncTriggerId,
params: {'ref': 'v1.2.3'},
);
if (job.timedOut) {
// responseTimeoutMs 초과. 워크플로우는 백그라운드에서 계속 실행
} else if (job.status == 'success' && job.output is Map) {
final url = (job.output as Map)['url'];
print('Deployed: $url');
}Embedded — Agent 운영
키오스크·전시 단말처럼 일반 앱 안에 Agent를 심는 시나리오예요.
첫 실행에서 enroll, 결과를 안전 저장소에 보관, 이후 부팅에선 그 자격으로 SSE를 구독해요.
import 'dart:async';
import 'package:deplite/deplite.dart';
Future<void> runAgent() async {
final stored = await secureStore.loadAgent();
final agent = DepliteAgent(
identity: stored.identity,
privateKey: stored.privateKey,
);
// 30초 heartbeat (기본값 일치)
Timer.periodic(const Duration(seconds: 30), (_) async {
try { await agent.heartbeat(); } catch (_) {}
});
// 메인 이벤트 루프
await for (final event in agent.events()) {
switch (event) {
case DeployEvent(payload: final p):
await _handleDeploy(agent, p);
case SyncWorkflowsEvent():
await agent.workflows.report(_loadLocalWorkflows());
case RevokeEvent():
return;
case PingEvent():
continue;
case UnknownEvent(name: final n):
print('unknown event: $n');
}
}
}
Future<void> _handleDeploy(DepliteAgent agent, DeployPayload payload) async {
try {
await agent.jobs.appendLogs(jobId: payload.jobId, items: [
LogItem(seq: 0, stream: LogStream.system, level: LogLevel.info, content: 'started'),
]);
final output = await runWorkflow(payload);
await agent.jobs.reportResult(
jobId: payload.jobId,
result: JobResult.success(output: output),
);
} catch (e) {
await agent.jobs.reportResult(
jobId: payload.jobId,
result: JobResult.failed(exitCode: 1, errorMessage: '$e'),
);
}
}secureStore는 예시명이에요.
실제로는 privateKey(raw 32바이트)는 암호화 후 저장하는 것을 추천드려요.
Embedded — 워크플로우 인벤토리 동기화
SyncWorkflowsEvent가 오면 현재 내가 실행 가능한 워크플로우 목록을 서버에 알려요.
실제 YAML 본문은 보내지 않고 이름과 메타만 보고해요.
Future<void> reportWorkflows(DepliteAgent agent) async {
await agent.workflows.report([
const WorkflowReport(
name: 'deploy-prod',
verboseSteps: ['build', 'push'],
secretsKeys: ['DB_URL'],
),
const WorkflowReport(name: 'healthcheck', verboseSteps: ['ping']),
]);
}에러 처리 — 재시도 가능한 케이스만 백오프
Future<T> runWithRetry<T>(Future<T> Function() block, {int max = 3}) async {
for (var i = 0; i < max; i++) {
try {
return await block();
} on DepliteAuthException {
rethrow; // 재시도 무의미
} on DepliteApiException catch (e) {
if (e.statusCode < 500 && e.statusCode != 429) rethrow;
if (i == max - 1) rethrow;
await Future.delayed(Duration(milliseconds: 500 * (1 << i)));
}
}
throw StateError('unreachable');
}관련 문서
최종 수정 일자: