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.
Statement under the Private Securities Litigation Reform Act of 1995
As a beta feature, Apex Transaction Finalizer is a preview and isn’t part of the “Services” under
your master subscription agreement with Salesforce. Use this feature at your sole discretion, and
make your purchase decisions only on the basis of generally available products and features.
Salesforce doesn’t guarantee general availability of this feature within any particular time frame or
at all, and we can discontinue it at any time. This feature is for evaluation purposes only, not for
production use. It’s offered as is and isn’t supported, and Salesforce has no liability for any harm or
damage arising out of or in connection with it. All restrictions, Salesforce reservation of rights,
obligations concerning the Services, and terms for related Non-Salesforce Applications and
Content apply equally to your use of this feature.
● Potential use-cases
● Design overview
● Scope and Limitations
● Demo of some use cases
● Apex Roadmap Highlights
● No easy way to retry jobs.
● Only option to alert on failure is poll AsyncApexJob
● One LimitException in a Queueable chain breaks it
● Challenges with persisting logs/warnings when
working with callouts
Async Apex is a black box.
BatchApexErrorEvent Unsolved Problems
● ❌ Queueable Apex, entirely.
● ❌ Event-driven error reporting requires
Salesforce to understand the job's work
● ❌ Logging when doing callouts still tricky
● ✅ Retry support
● ✅ Inspect failed state
● ✅ Notify admins
● ❌ Only for batch Apex
A partial solution with Winter '19
What is a Transaction Finalizer?
○ When a Queueable fails, there's no good way to retry/recover.
○ Sometimes these failures are not-recoverable, like LimitException, or a gack.
○ Only real option is to save AsyncApexJob somewhere, and poll for status. 🤮
● Transaction Finalizer is an action that, when attached from a queueable job, is invoked by
Apex runtime after the completion of the queueable execution.
● A transaction finalizer is executed not only when the queueable (that attached the finalizer)
completes successfully, but also when a queueable completes with errors (failed).
1. Re-enqueuing Finalizer: A finalizer that re-enqueues a new queueable job instance (of
same apex type as the queueable that attached it) when the queueable job that attached
the finalizer fails.
2. Logging Finalizer: A finalizer that persists the log. Log buffer will be part of finalizer state
and the queueable that attached the finalizer will log to this buffer during the queueable
execution. At the end of the queueable execution, finalizer shall save the log to DB, even
queueable fails. If this log buffer was not part of finalizer and if the queueable were to add
the log directly to the db, it would be rolled back when queueable fails.
3. Chaining Finalizer: Chain the next queueable in a multi-step execution. If the next
queueable Q is enqueued in a queueable job P, then Q will not be executed if P fails.
However, if the queueable Q is enqueued in the finalizer attached by the P, then Q will be
executed even when P fails.
Design: Sequence diagram
Logging Finalizer and Queueable using it
● Finalizer does not share the Apex contexts with the Queueable that attached the finalizer
○ New limits, new heap. Static and instance state other than the Finalizer is discarded.
● However, Finalizer and the Queueable that attached the finalizer share same Request ID. Use this
Request ID when using Event Monitoring to view logs of Queueable and corresponding Finalizer
● Finalizer instance created by the queueable is serialized (with its state) at the end of the queueable
execution completion, to allow for above mentioned contexts to be released and created again. A new
instance of Finalizer is created after that by deserializing previously serialized state.
○ This state remains mutable after the finalizer is attached!
● DB transactions in Queueable and Finalizer are completely independent of each other.
○ Both commit or rollback independently, as two distinct Apex contexts.
● Finalizer executes immediately after Queueable completes execution, on the same thread.
○ This means that the most extreme kinds of Salesforce failures where we are unable to serialize
the Finalizer state may prevent the finalizer from running.
● Finalizer quiddity is QTXF (different from that of Queueable).
Scope and Limitations
● Finalizers are available only in API v52.0 and higher for GA. v50 and above for beta-level.
● Finalizers are available for Queueable jobs only.
● Only one Finalizer can be attached from a single Queueable job.
○ Queueable can still enqueue another queueable job
● Finalizer does not execute if the queueable job that attaches the finalizer is aborted or
unable to start execution.
○ Finalizer will be executed when the queueable begins execution, attaches finalizer and completes
either successfully or fails. If the queueable is aborted before it begins execution, then the finalizer
will not be executed because the queueable logic that attaches finalizer is not yet executed.
● Finalizer can enqueue a Queueable job or Future - maximum one (1) Asynchronous job.
● Finalizer runs with Synchronous Apex Limits (other than the only one async job caveat)
● Apex Developer Guide: Transaction Finalizers
● "Learn MOAR in Spring ’20 Introducing Transaction Finalizers"
● "Learn MOAR in Spring ’20 Implementing Promises with Transaction Finalizers"
Apex Roadmap Highlights
User-Mode Database Operations
● New Database.* methods that automatically enforce CRUD/FLS/Sharing
○ Compatible with upcoming features, like Restriction/Scoping rules pilots
○ Full support for SOSL, polymorphic lookups, and all the other edge cases!
○ Available as a dynamic API (overloads of existing methods)
■ Database.insert(SObject, AccessLevel);
■ Database.query(String, AccessLevel);
○ Compile-time support ([SELECT ….]) planning for next pilot iteration.
● Secure: no edge cases or possible developer mistakes that subvert application security
● Fast: Apex de-escalates permissions, out of system mode
○ No redundant FLS/CRUD checks on top of the system mode escalation
In the distant future we are looking to make this the implicit default for Apex SOQL/SOSL/DML
In pilot. Nominations available starting end of May.
Exploring: allowing speciﬁcation of an escalation PermissionSet, for cases where Apex needs elevated rights, but wants to
limit them to a known set.
DataWeave in Apex?
DataWeave is a programming language designed for transforming data.
It is MuleSoft’s primary language for data transformation.
DataWeave allows users to easily perform a common use case for integration developers:
read and parse data from one format, transform it, and write it out as a diﬀerent format.
For example, a DataWeave script could take in a simple CSV ﬁle and transform it into an array
of complex JSON objects. It could take in XML and write the data out to a ﬂat ﬁle format.
DataWeave allows the developer to focus on the transformation logic instead of worrying about
the speciﬁcs of reading, parsing, and writing speciﬁc data formats in a performant way.
Pilot planned for Winter '22. Safe Harbor.
A Quick Sample
Using DataWeave in Apex
1. Create a DataWeave script under dataweave/*.dwl
2. Deploy via SFDX or Metadata API
3. Construct a DataWeave.Script instance in Apex:
DataWeave.Script instance = new DataWeave.Script.Foo(input); [for GA]
DataWeave.Script.createScript('Foo', input); [Pilot]
4. Run it:
DataWeave.Output result = instance.run();
Draft Proposal: Apex Runtime API is not yet ﬁnalized