타입 | 내용 | 용례 |
---|---|---|
Future 메소드 | 자체 스레드에서 실행, 리소스를 사용할 수 있을 때가지 시작되지 않음 | 웹 서비스 콜아웃 |
Batch Apex | 일반적인 거버너 리밋을 넘는 대규모 작업 수행 | 데이터 삭제, 레코드 아카이빙 |
Queueable Apex | 퓨처 메소드와 유사하나, 추가적인 체이닝을 제공하고 더 복잡한 데이터 유형 사용 가능 | 웹 서비스에서 순서가 있는 작업이 필요할 때 |
Scheduled Apex | 지정된 시간에 APEX 실행 예약 | 매일,주간으로 반복되는 업무 |
Enqueue
요청이 큐로 적재됨. 해당 요청을 처리하기 위해 적절한 데이터와 함께 요청을 대기열에 넣는다.
Persistence
대기열에 있는 요청은 지속되며, 장애 복구를 위해 영구 저장소에 저장되고 트랜잭션을 제공
Dequeue
요청을 마치면 요청은 큐에서 제거되고, 처리가 실패하면 트랜잭션이 요청이 손실되지 않도록 보장한다.
@future
메소드가 사용되는 경우외부 웹 서비스에 대한 콜아웃: 트리거에서 콜아웃을 하거나 DML 작업을 수행한 후 콜아웃을 하는 경우 future 또는 queueable 메서드를 사용해야 함
.
트리거의 콜아웃은 콜아웃의 수명 동안 데이터베이스 연결을 열어두며 이는 멀티테넌트 환경에서 금지됨.
별도의 스레드에서 실행하려는 작업 : 여기에는 리소스를 많이 소모하는 계산이나 레코드 처리 등이 포함
혼합 DML 오류를 방지하기 위해 다른 sObject 유형에서 DML 작업을 분리: 자세한 내용은 DML 작업에서 함께 사용할 수 없는 sObject를 참조 (예외 경우임)
static 메소드
여야 한다.void 유형만 반환
한다.기본 데이터 유형
, 기본 데이터 유형 배열
, 기본 데이터 유형 컬렉션
이여야 한다. -- 표준/사용자 정의 개체를 파라미터로 사용 불가 ==> 비동기가 실행되는 중간에 개체가 변경될 수 있기 때문!레코드 ID 리스트를 전달
해서 사용순서대로 실행된다는 보장
이 없음 => 두 메서드가 같은 레코드를 업데이트하면 락이 걸리거나, 런타임 에러 발생할 수 있음. public class SomeClass {
@future
public static void someFutureMethod(List<Id> recordIds) {
List<Account> accounts = [Select Id, Name from Account Where Id IN :recordIds];
// process account records to do awesome stuff
}
}
//가상 mock 콜아웃 응답기
@isTest
public class SMSCalloutMock implements HttpCalloutMock {
public HttpResponse respond(HttpRequest req) {
// Create a fake response
HttpResponse res = new HttpResponse();
res.setHeader('Content-Type', 'application/json');
res.setBody('{"status":"success"}');
res.setStatusCode(200);
return res;
}
}
//
@IsTest
private class Test_SMSUtils {
@IsTest
private static void testSendSms() {
Test.setMock(HttpCalloutMock.class, new SMSCalloutMock());
Test.startTest();
SMSUtils.sendSMSAsync('111', '222', 'Greetings!');
Test.stopTest();
// runs callout and check results
List<SMS_Log__c> logs = [select msg__c from SMS_Log__c];
System.assertEquals(1, logs.size());
System.assertEquals('success', logs[0].msg__c);
}
}
Database.Batchable
인터페이스를 구현해야함start
/ execute
/ finish
메소드를 오버라이딩 재정의 해야함.start
처음
한번 호출된다.Database.QueryLocator
오브젝트를 반환하거나, 잡에 넘길 레코드나 개체를 포함한Iterable을 반환QueryLocator
: 간단한 SOQL (거버너 리밋 우회, 최대 5000만개의 레코드 쿼리 가능), 만약 복잡한 구문을 처리해야한다면 커스텀 Iterable을 사용하기execute
Database.BatchableContext
를 참조finish
public class MyBatchClass implements Database.Batchable<sObject> {
public (Database.QueryLocator | Iterable<sObject>) start(Database.BatchableContext bc) {
// collect the batches of records or objects to be passed to execute
}
public void execute(Database.BatchableContext bc, List<P> records){
// process each batch of records
}
public void finish(Database.BatchableContext bc){
// execute any post-processing operations
}
}
//이후 호출해서 배치 수행.
MyBatchClass myBatchObject = new MyBatchClass();
Id batchId = Database.executeBatch(myBatchObject, 100);
//이는 Job Queue에서 관리 가능
AsyncApexJob job = [SELECT Id, Status, JobItemsProcessed, TotalJobItems, NumberOfErrors FROM AsyncApexJob WHERE ID = :batchId ];
Database.Stateful
을 클래스에서 정의하면 트랜잭션간 작업간 상태를 유지할 수 있음. Queueable
apex가 사용되는 경우public class UpdateParentAccount implements Queueable {
private List<Account> accounts;
private ID parent;
public UpdateParentAccount(List<Account> records, ID id) {
this.accounts = records;
this.parent = id;
}
public void execute(QueueableContext context) {
for (Account account : accounts) {
account.parentId = parent;
// perform other processing or callout
}
update accounts;
}
}
// find all accounts in ‘NY’
List<Account> accounts = [select id from account where billingstate = ‘NY’];
// find a specific parent account for all records
Id parentId = [select id from account where name = 'ACME Corp'][0].Id;
// instantiate a new instance of the Queueable class
UpdateParentAccount updateJob = new UpdateParentAccount(accounts, parentId);
// enqueue the job for processing
ID jobID = System.enqueueJob(updateJob);
public class FirstJob implements Queueable {
public void execute(QueueableContext context) {
// Awesome processing logic here
// Chain this job to next job by submitting the next job
System.enqueueJob(new SecondJob());
}
}
Scheduler
apex가 사용되는 경우public class SomeClass implements Schedulable {
public void execute(SchedulableContext ctx) {
// awesome code here
}
}
RemindOpptyOwners reminder = new RemindOpptyOwners();
// Seconds Minutes Hours Day_of_month Month Day_of_week optional_year
String sch = '20 30 8 10 2 ?';
String jobID = System.schedule('Remind Opp Owners', sch, reminder);