1.Queueable Apex
Queueable Apex是future的升级版。它可以
①:可以使用基本数据类型以外的数据类型作为参数
②:System.enqueueJob()函数来调用
③:执行中的job可以继续调用下一个job
虽然比future好用,但是在既需要执行同期处理,又需要执行非同期处理的时候,一般选用future。
基本语法:
public class SomeClass implements Queueable { public void execute(QueueableContext context) { // awesome code here } }
举例代码:
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);
SELECT Id, Status, NumberOfErrors FROM AsyncApexJob WHERE Id = :jobID
测试代码:
@isTest public class UpdateParentAccountTest { @testSetup static void setup() { List<Account> accounts = new List<Account>(); // add a parent account accounts.add(new Account(name='Parent')); // add 100 child accounts for (Integer i = 0; i < 100; i++) { accounts.add(new Account( name='Test Account'+i )); } insert accounts; } static testmethod void testQueueable() { // query for test data to pass to queueable class Id parentId = [select id from account where name = 'Parent'][0].Id; List<Account> accounts = [select id, name from account where name like 'Test Account%']; // Create our Queueable instance UpdateParentAccount updater = new UpdateParentAccount(accounts, parentId); // startTest/stopTest block to force async processes to run Test.startTest(); System.enqueueJob(updater); Test.stopTest(); // Validate the job ran. Check if record have correct parentId now System.assertEquals(100, [select count() from account where parentId = :parentId]); } }
2.スケジュール済みの Apex
可以指定时间来执行。
基本语法:
实现Schedulable接口,重写execute函数,后可以通过System.schedule()来调用。
public class SomeClass implements Schedulable { public void execute(SchedulableContext ctx) { // awesome code here } }
举例代码
public class RemindOpptyOwners implements Schedulable { public void execute(SchedulableContext ctx) { List<Opportunity> opptys = [SELECT Id, Name, OwnerId, CloseDate FROM Opportunity WHERE IsClosed = False AND CloseDate < TODAY]; // Create a task for each opportunity in the list TaskUtils.remindOwners(opptys); } }
通过System.Schedule函数来调用
需要注意的是第二个参数从左到右分别对应,「秒,分,时,日,月,曜日,年」(其中年可以省略)
比如说
- ‘0 0 13 * * ?’:毎日13時に実行
- ‘0 0 10 ? * MON-FRI’:月~金の10時に実行
- ‘0 0 * * * ?’:毎時0分に実行
- ‘0 30 * * * ?’:毎時30分に実行
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);
测试代码
@IsTest private class RemindOppyOwnersTest { // Dummy CRON expression: midnight on March 15. // Because this is a test, job executes // immediately after Test.stopTest(). public static String CRON_EXP = '0 0 0 15 3 ? 2042'; @IsTest static void testScheduledJob() { // Create some out of date Opportunity records List<Opportunity> opptys = new List<Opportunity>(); Date closeDate = Date.today().addDays(-7); for (Integer i=0; i<10; i++) { Opportunity o = new Opportunity( Name = 'Opportunity ' + i, CloseDate = closeDate, StageName = 'Prospecting' ); opptys.add(o); } insert opptys; // Get the IDs of the opportunities we just inserted Map<Id, Opportunity> opptyMap = new Map<Id, Opportunity>(opptys); List<Id> opptyIds = new List<Id>(opptyMap.keySet()); Test.startTest(); // Schedule the test job String jobId = System.schedule('ScheduledApexTest', CRON_EXP, new RemindOpptyOwners()); // Verify the scheduled job has not run yet. List<Task> lt = [SELECT Id FROM Task WHERE WhatId IN :opptyIds]; System.assertEquals(0, lt.size(), 'Tasks exist before job has run'); // Stopping the test will run the job synchronously Test.stopTest(); // Now that the scheduled job has executed, // check that our tasks were created lt = [SELECT Id FROM Task WHERE WhatId IN :opptyIds]; System.assertEquals(opptyIds.size(), lt.size(), 'Tasks were not created'); } }