Description
Part of what truly makes a platform is an ability to integrate with third party devices, servers and software. Join Ami Assayag and Kirk Steffke from CRM Science and Developer Evangelist Josh Birk as they breakdown examples of using Apex for integration solutions. Apex has robust methods for handling both inbound requests into Salesforce and outbound calls into third party systems. This webinar will break down how Apex can be used in these cases as well as how to test the code once it is up and running.
Key Takeaways
- How Apex fits into an integration solution
- Using Apex to create custom endpoints
- Handling outbound calls with Apex
- How to achieve test coverage with mock interfaces
Intended Audience
Developers with Apex experience looking to integrate with either existing API’s or expanding the functionality of Salesforce API’s.
2. #forcewebina
r
Statement under the Private Securities Litigation Reform Act of 1995:
This presentation may contain forward-looking statements that involve risks, uncertainties, and assumptions. If any such uncertainties materialize or if any of
the assumptions proves incorrect, the results of salesforce.com, inc. could differ materially from the results expressed or implied by the forward-looking
statements we make. All statements other than statements of historical fact could be deemed forward-looking, including any projections of product or service
availability, subscriber growth, earnings, revenues, or other financial items and any statements regarding strategies or plans of management for future
operations, statements of belief, any statements concerning new, planned, or upgraded services or technology developments and customer contracts or use of
our services.
The risks and uncertainties referred to above include – but are not limited to – risks associated with developing and delivering new functionality for our service,
new products and services, our new business model, our past operating losses, possible fluctuations in our operating results and rate of growth, interruptions
or delays in our Web hosting, breach of our security measures, the outcome of any litigation, risks associated with completed and any possible mergers and
acquisitions, the immature market in which we operate, our relatively limited operating history, our ability to expand, retain, and motivate our employees and
manage our growth, new releases of our service and successful customer deployment, our limited history reselling non-salesforce.com products, and utilization
and selling to larger enterprise customers. Further information on potential factors that could affect the financial results of salesforce.com, inc. is included in our
annual report on Form 10-K for the most recent fiscal year and in our quarterly report on Form 10-Q for the most recent fiscal quarter. These documents and
others containing important disclosures are available on the SEC Filings section of the Investor Information section of our Web site.
Any unreleased services or features referenced in this or other presentations, press releases or public statements are not currently available and may not be
delivered on time or at all. Customers who purchase our services should make the purchase decisions based upon features that are currently available.
Salesforce.com, inc. assumes no obligation and does not intend to update these forward-looking statements.
Forward-Looking Statement
4. #forcewebina
r
Go Social!
@salesforcedevs / #forcewebinar
Salesforce Developers
Salesforce Developers
Salesforce Developers
This webinar is being recorded! The video will be posted to YouTube and the
webinar recap page (same URL as registration).
5. #forcewebina
r
Agenda
• What is Asynchronous Process?
• Why we need it?
• Types of Asynchronous Processes in Salesforce
• Usage and Examples
• Comparison of various Asynchronous Processes
• Appendix
• Recap
8. #forcewebina
r
Asynchronous Process - Definition
• In computer
programs,
asynchronous
operation means
that a process
operates
independently of
other processes
9. #forcewebina
r
Asynchronous vs Synchronous
Synchronous
• Quick and
Immediate Actions
• Transactions are
immediate and
serial
• Normal governor
limits
Asynchronous
• Actions that will not
block the
transaction pr
process
• Duration is not a
Priority
• Higher governor
limits
19. #forcewebina
r
Use Cases
• Send Data to an External System on a Insert or Update
• Complex Calculations or Analysis based on Data in Salesforce
• Report Runs
• Callouts to External Systems
21. #forcewebina
r
Use Case – Logic on Millions of Rows
• Supports complex logic on very
large datasets
• Scalable, robust, asynchronous
execution platform
• Scheduled or programmatically
executed
• Eliminate ‘data processing’
integrations
• Data cleansing, augmentation
• Automated batch process
24. #forcewebina
r
Scenario
• Goal: Populate Account’s Billing Longitude/Latitude based on
Billing Address
• Assume we have a method that calls out to a web service and
returns the lon/lat for a given Account, in the Geocoding Utils class
public static LonLat geocodeAccount(Account acct) { … }
LonLat is a class with 2 Double properties.
• Solution: Write a trigger that calls this method.
• Problem: You can’t call out to a web service from a trigger.
25. #forcewebina
r
@future
• A public static method, decorated with @future
• Arguments:
• Primitives (Integer, String, etc.)
• Collections of primitives (List, Map, Set)
• NOT Sobjects or Apex objects
• You can use JSON.serialize() and pass in a String
• Returns void
26. @future
public class GeocodingUtils {
@future (callout=true)
public static void geocodeAccountFuture(Id accountId) {
Account acct =
[select Id, BillingStreet, BillingCity, BillingState, BillingPostalCode, BillingCountry
from Account
where Id = :accountId];
LonLat coordinates = geocodeAccount(acct);
if (coordinates != null) {
acct.BillingLongitude = coordinates.lon;
acct.BillingLatitude = coordinates.lat;
update acct;
}
}
}
27. @future – Account trigger
trigger Account on Account (before insert, before update) {
if (Trigger.isBefore && (Trigger.isInsert || Trigger.isUpdate)) {
// For each new Account or each existing Account whose Address has changed, geocode it
for (Account acct : Trigger.new) {
if (Trigger.isInsert ||
(Trigger.isUpdate && GeocodingUtils.addressChanged(acct, Trigger.oldMap.get(acct.Id)))) {
// Geocode the Account's address
GeocodingUtils.geocodeAccountFuture(acct.Id);
}
}
}
}
28. #forcewebina
r
Queueable Class
• A public class that implements the Queueable interface
• Includes an execute method that accepts only a QueueableContext
parameter
• The execute method can access instance properties for the
class
• Returns void
• Launch by calling System.enqueueJob(cls) with an instance of the
class.
• Returns an AsyncApexJob Id
29. Queueable Apex
public class GeocodingQueueable implements Queueable, Database.AllowsCallouts {
public Account[] lstAccounts = new Account[]{};
public void execute(QueueableContext ctx) {
// Process as many Accounts as we can
Account[] lstProcessed = new Account[]{};
Integer numProcessed;
for (numProcessed=0;
numProcessed < Limits.getLimitCallouts() && numProcessed<lstAccounts.size();
numProcessed++) {
Account acctGeo = lstAccounts[numProcessed];
GeocodingUtils.LonLat coordinates = GeocodingUtils.geocodeAccount(acctGeo);
if (coordinates != null) {
acctGeo.BillingLongitude = coordinates.lon;
acctGeo.BillingLatitude = coordinates.lat;
lstProcessed.add(acctGeo);
}
}
30. Queueable Apex
…
update lstProcessed;
// Remove the ones we just processed from the list.
for (Integer i=0; i<numProcessed; i++) {
lstAccounts.remove(0);
}
// If there are any remaining Accounts, chain a new Async job to process them.
// NOTE: As of Spring 16, a chained Queueable job cannot do a callout, so the next
// run of this execute() method will fail!
if (!lstAccounts.isEmpty()) {
Id jobID = System.enqueueJob(this);
}
}
}
31. Queueable Apex– Account trigger
trigger Account on Account (before insert, before update) {
if (Trigger.isBefore && (Trigger.isInsert || Trigger.isUpdate)) {
Account[] lstAccounts = new Account[]{};
for (Account acct : Trigger.new) {
if (Trigger.isInsert ||
(Trigger.isUpdate && GeocodingUtils.addressChanged(acct, Trigger.oldMap.get(acct.Id)))) {
Account acctGeo = new Account(Id=acct.Id);
acctGeo.BillingStreet = acct.BillingStreet;
acctGeo.BillingCity = acct.BillingCity;
acctGeo.BillingState = acct.BillingState;
acctGeo.BillingPostalCode = acct.BillingPostalCode;
acctGeo.BillingCountry = acct.BillingCountry;
lstAccounts.add(acctGeo);
}
}
if (!lstAccounts.isEmpty()) {
// Geocode the Account's address
GeocodingQueueable cls = new GeocodingQueueable();
cls.lstAccounts = lstAccounts;
Id jobID = System.enqueueJob(cls);
}
}
}
32. #forcewebina
r
Batchable Class
• A global class that implements the Database.Batchable interface
• Includes:
• Start method – identifies the scope (list of data to be processed)
• Execute method – processes a subset of the scoped records
• Finish method – does any post-job wrap-up
• Additional interfaces:
• Database.Stateful
• Database.AllowCallouts
33. #forcewebina
r
Batchable Class
• Launch by callling Database.executeBatch(cls) with an instance of
the class and an optional scope size
• Default scope size is 200
• Returns an AsyncApexJobId
34. Batch Apex
global class GeocodingBatch implements Database.Batchable<SObject>,
Database.AllowsCallouts, Database.Stateful {
global Integer numberOfAccountsUpdated = 0;
// Start method gets all Accounts that need to be geocoded
global Database.QueryLocator start(Database.BatchableContext bc) {
String query = 'select id from Account where Need_to_Geocode__c = true';
return Database.getQueryLocator(query);
}
35. Batch Apex
global void execute(Database.BatchableContext bc, List<SObject> lstSObjects) {
// Get the Accounts
Account[] lstAccounts =
[select Id, BillingStreet, BillingCity, BillingState, BillingPostalCode, BillingCountry
from Account where Id in :lstSObjects];
for (Account acct : lstAccounts) {
// Geocode the Account and save the results
GeocodingUtils.LonLat coordinates = GeocodingUtils.geocodeAccount(acct);
if (coordinates != null) {
acct.BillingLongitude = coordinates.lon;
acct.BillingLatitude = coordinates.lat;
}
acct.Need_to_Geocode__c = false;
}
update lstAccounts;
numberOfAccountsUpdated += lstAccounts.size();
}
36. Batch Apex
global void finish(Database.BatchableContext bc) {
// Send an email to let someone know how many Accounts we updated
System.debug('Number of Accounts updated: ' + numberOfAccountsUpdated);
}
} // End of class
37. Batchble Apex– Account trigger
trigger Account on Account (before insert, before update) {
if (Trigger.isBefore && (Trigger.isInsert || Trigger.isUpdate)) {
// For each new Account or each existing Account whose Address has changed,
// flag it to be geocoded later
for (Account acct : Trigger.new) {
if (Trigger.isInsert ||
(Trigger.isUpdate && GeocodingUtils.addressChanged(acct, Trigger.oldMap.get(acct.Id)))) {
acct.Need_to_Geocode__c = true;
}
}
}
}
39. Schedulable Apex
global class GeocodingSchedulable {
global void execute(SchedulableContext ctx) {
GeocodingBatch cls = new GeocodingBatch();
Integer batchSize = (Limits.getLimitCallouts() < 200) ? Limits.getLimitCallouts() : 200;
Id jobId = Database.executeBatch(cls, batchSize);
}
}
40. #forcewebina
r
Schedulable Class
• Schedule by calling
System.Schedule(‘job name’, cron expression, cls)
• Job Name is found in AsyncApexJob object
• Cron expression can be complex
• Returns an AsyncApexJob Id
41. #forcewebina
r
Schedulable Class
• Cron expression string
seconds minutes hours day_of_month month day_of_week optional_year
• Run at 30 minutes past midnight on Jan 1 every year
GeocodingSchedulable cls = new GeocodingSchedulable();
System.Schedule('Geocode on Jan 1', '0 30 0 1 1 ? *', cls);
• Run every hour
GeocodingSchedulable cls = new GeocodingSchedulable();
System.Schedule('Geocode on Jan 1', '0 0 * * * ? *', cls);
• Check the Apex Language Reference for details
42. #forcewebina
r
Summary of Techniques
• @future – static method, simple arguments, no monitoring, no
chaining
• Queueable – class with instance variables, can monitor, can chain
(within limits)
• Batch Apex – class with instance variables, great for large numbers
of records, can monitor
• Schedulable – class with instance variables, runs one or at
43. #forcewebina
r
Monitoring Async Apex
• For Queueable and Batchable
• When you launch the job, you get an AsyncApexJob Id
• Setup | Monitoring | Apex Jobs
• See doc for description of Status values
• For Schedulable
• When you schedule the job, you get a CronTrigger Id
• When it runs, it’s added to AsyncApexJobs
• Setup | Monitoring | Scheduled Jobs
• Add a list view filter for Type = Scheduled Apex
44. #forcewebina
r
Testing Async Apex
• Before launching the job, do Test.startTest()
• After launching the job, do Test.stopTest()
• One instance of the job will run before Test.stopTest() returns