백그라운드·예약 작업 실행하기
작업 선언·실행 요청·예약과 실제 처리 결과를 확인합니다.
백그라운드·예약 작업 실행하기
앱 자체의 queue worker나 서버 cron을 설치하지 않고 AppWorkContribution과 AppWorkDispatcher를 사용합니다. 개발 데이터 만들기의 테넌트 소유 Example 리소스를 준비하세요. 여기서는 고정된 예제 레코드 하나만 생성합니다. 사용자 권한을 위임받아 수행하는 업무 예제가 아닙니다.
작업 구현과 선언
src/Work/EnsureExample.php를 만듭니다:
<?php
declare(strict_types=1);
namespace Nexia\Apps\Acme\Workshop\Work;
use InvalidArgumentException;
use Nexia\Apps\Acme\Workshop\Models\Example;
use Nexia\AsyncWork\AppWorkInvocation;
use Nexia\AsyncWork\Contracts\AppWorkHandler;
final class EnsureExample implements AppWorkHandler
{
public function handle(AppWorkInvocation $invocation): void
{
if ($invocation->key !== 'workshop.example.ensure' || $invocation->payload !== []) {
throw new InvalidArgumentException('Unexpected work payload.');
}
Example::firstOrCreate(
['public_id' => '018d4f35-84ed-4ce4-a421-277f7d872601'],
['name' => 'Background example'],
);
}
}src/Contribution/WorkshopWork.php를 추가합니다. 생성된 Manifest가 이 경로를 발견합니다:
<?php
declare(strict_types=1);
namespace Nexia\Apps\Acme\Workshop\Contribution;
use Nexia\Apps\Acme\Workshop\Work\EnsureExample;
use Nexia\AsyncWork\AppWorkDefinition;
use Nexia\AsyncWork\Contracts\AppWorkContribution;
final class WorkshopWork implements AppWorkContribution
{
public static function appWork(): array
{
return [new AppWorkDefinition('workshop.example.ensure', EnsureExample::class)];
}
}실행 요청
생성된 인증 Route·Controller 안에 POST 동작을 추가하고 아래 본문을 사용하세요. Request 검증과 리소스 Policy를 유지하며 요청자가 작업 키나 handler 클래스를 고르게 하지 않습니다. 이 예제는 의도적으로 빈 payload를 사용합니다:
use Nexia\AsyncWork\Contracts\AppWorkDispatcher;
$this->authorize('create', \Nexia\Apps\Acme\Workshop\Models\Example::class);
app(AppWorkDispatcher::class)->dispatch(
'workshop.example.ensure',
[],
'workshop.example.ensure.initial',
);
return response()->json(['accepted' => true], 202);고정된 멱등 키는 한 번의 초기화 요청을 뜻합니다. 실제 업무에서는 작업 식별자를 저장하고 동일 작업의 재시도에 재사용하세요. 새로운 업무에는 새로운 키가 필요합니다. 작업 자체는 여러 번 실행될 수 있으므로 handler도 중복 효과를 막아야 합니다. 이 예제는 고유 레코드 식별자를 사용합니다.
샌드박스 dispatcher를 앱 트랜잭션 안에서 호출하면 커밋 이후 전송합니다. 트랜잭션 outbox는 아니므로 커밋과 enqueue 사이 실패에 대비해 앱 작업 기록을 보관하고 같은 키로 재시도해야 합니다. enqueue 성공만으로 업무 완료를 표시하지 마세요.
필요한 경우에만 예약 추가
같은 contribution에 인터페이스와 메서드를 추가합니다. 실행 대상 설치와 트리거는 Core가 관리하고 앱은 5개 필드 cron 표현식과 제한된 payload를 선언합니다:
use Nexia\AsyncWork\AppWorkSchedule;
use Nexia\AsyncWork\Contracts\AppWorkScheduleContribution;
// Also implement AppWorkScheduleContribution on WorkshopWork.
public static function appWorkSchedules(): array
{
return [new AppWorkSchedule(
key: 'workshop.example.hourly',
workKey: 'workshop.example.ensure',
cron: '0 * * * *',
)];
}예약 작업에는 앱을 설치한 사용자의 권한이 자동으로 주어지지 않습니다. 사용자 권한이나 조직 검증을 건너뛰지 마세요. AppWorkInvocation은 executionId·key·attempt·payload를 전달하며 사용자·법인 DTO가 아닙니다. 업무별 권한 근거와 대상을 명시적으로 해석해야 합니다. 플랫폼 callback은 AppWorkDefinition.platformCallbacks에 선언하며 임의 이름을 넣는다고 권한이 부여되지 않습니다.
실행·복구 확인
- 프로젝트
nexia dev로 동기화하고 준비 완료를 기다립니다. Example 생성·조회 권한을 부여합니다. - 보호된 POST를 호출하고 Examples 목록에 레코드가 나타나는지 확인합니다.
202는 접수만 뜻합니다. - 같은 요청과 격리된 테스트의 handler 전달을 반복합니다. 레코드는 하나이고 수정한 이름도 유지돼야 합니다.
- 권한 없는 호출·잘못된 payload·handler 실패를 확인합니다. 실패한 업무를 성공으로 처리하지 않습니다.
- 예약 작업은 런타임 사용 중 실행 시각이 지나 실제 처리됐는지 확인합니다. 선언 등록만으로 관리형 scheduler 실행을 증명할 수 없습니다. 실행되지 않으면 작업 식별자로 지원 요청하세요.
커밋된 업무 이벤트에 반응하는 경우에는 이벤트와 비동기 작업을 사용합니다.