6

This question is somewhat related to my other open question on the asynch/synch topic.

Assume I would have an algorithm that could tell me that for a given customer org (data volumes and other factors) my function A will run into limits. How would I have to implement it that it can be easily be called synchronously and asynchronously?

Please also assume that just calling my method as a @future would not suffice. I really need it as a Batch.

Am I thinking to complicated or is there a pattern or best practice on how to structure my code for those cases.

FYI: I changed those question back to unanswered as one important aspect is not yet answered. How to structure setup/state initialisation code that in Batch classes goes into the constructor or the start method. Where would that go if the functionality is called synchronuously?

  • What parameters does function A take? In order to formulate an answer for you I'm interested to know what inputs to it, will have it consume more or less governor limits. Typically I use a service layer pattern to encapsulate the processing and transaction of the work and allow other callers (such as batch, future, vf controllers etc) to consume it. So if function A in this context is a service method, its important to know the parameters. wiki.developerforce.com/page/… – Andrew Fawcett May 1 '13 at 7:35
  • 1
    Decided to have a go at an answer for you, hopefully you'll find it useful to learn more about the principle and its further benefits, enjoy! :-) – Andrew Fawcett May 1 '13 at 8:09
7

I follow a pattern known as the Service Layer. If you can elaborate on your 'function a' signature and needs I can provide some more specific examples for you, but this should give the general idea.

Service Layer, “Defines an application's boundary with a layer of services that establishes a set of available operations and coordinates the application's response in each operation.” Martin Fowler / Randy Stafford, EAA Patterns

In an Apex world it essentially encapsulates all your applications process logic in single layer that is agnostic of the callers, be they Batch Apex, Future, Apex Triggers, VF Controllers etc.... If you follow this practice closely you can even turn such things into a public Apex or REST API for your application quite easily.

enter image description here

This is an example of such a service method.

public class OpportunityService
{
    public static void applyDiscounts(Set<ID> opportunityIds, Decimal discountPercentage)

This is then consumed by a VF controller like so...

public PageReference applyDiscounts()
{
    try
    {
        // Apply discount entered to the selected Opportunities
        OpportunitiesService.applyDiscounts(
           new Map<Id,SObject>(standardSetController.getSelected()).keyValues(),
           DiscountPercentage);
    }
    catch (Exception e)
    {
        ApexPages.addMessages(e);
    }          
    return ApexPages.hasMessages() ? null : standardController.view();               
}

Or a Batch Apex class like so...

public with sharing class DiscountOpportunities
    implements Database.Batchable<sObject>
{
    public Decimal DiscountPercentage {get;set;}

    public Database.QueryLocator start(Database.BatchableContext BC) { ... }

    public void execute(Database.BatchableContext BC, List<sObject> scope)
    {
        try
        {
            OpportunitiesService.applyDiscounts(
                new Map<Id,SObject>(scope).keyValues(),DiscountPercentage);
        }
        catch (Exception e)
        {
            // Email error, log error, chatter error etc..
        }
    }

    public void finish(Database.BatchableContext BC) { ... }
}

There are a few other examples in the article linked below.

Designing a Service Layer. In either case the transactional scope and containment of the logic is managed entirely by the service layer, the callers responsibility is only to pass in the correct information, interpret responses and handle any Apex exceptions accordingly. Note also that service methods take bulkified parameters to match most callers needs and to better enforce bulkifcaiton within the service logic itself.

Further Reading. You can read more about this sample code, the guidelines and and other Apex Enterprise Patterns link within here. I'd be keen to know more about the signature of function A so I can perhaps taylor this answer a bit further for you.

Hope this helps!

  • I just read your recent blog post and your amazing pattern github repo. This answered more than this specific question. I would love to read more of this ;-) – Robert Sösemann May 1 '13 at 16:47
  • 1
    Service logic is typically about the tasks or complex processes that require interaction and interaction with many objects. Domain logic is scoped to a specific object and its own behaviour (so hence its more aligned with trigger type logic and other stuff logic related just to that object). So in a sense the service layer is really like a conductor for how all your objects work together to perform a certain process or task. – Andrew Fawcett May 2 '13 at 11:48
  • 1
    It sounds like aspects of it is service code (as it reads and updates across many objects), so consider a service method to encapsulate. If you don't feel you can factor it further into domain classes then don't. Though do study the code path of the OpportunitiesService.applyMethod to see how you can delegate down to methods on your domain classes if desired. Key behaviours of the domain class are validation and defaulting, though you can invoke other logic. As long as your business behaviour is somewhere below your service layer your already factoring well for the future already, IMHO! – Andrew Fawcett May 8 '13 at 20:38
  • 1
    +1 Good to see @AndrewFawcett pushing hard on pattern usage in Force.com world, your wiki post about enterprise patterns was nice. – Abhinav Gupta May 23 '13 at 17:03
  • 1
    @AbhinavGupta Thanks! I'm starting this weekend the final article on mapper/selector pattern! :) – Andrew Fawcett May 24 '13 at 11:27
6

I recently read a response from @ZachElrath about this very type of implementation. Maybe he could chime in on things learned since Sept. 2011?

Developerforce: Runnig Apex Job realtime

  • That's exactly how I'd do it. Just use the same code! You could put the content of execute into another class which takes a list of the appropriate object type too of course. – Matt Lacey May 1 '13 at 7:38
  • This solution and the one below by @Robert are simple and good for the purpose. I like this one better, as execute() is overloaded nicely. – Abhinav Gupta May 23 '13 at 16:50
4

This is how I solved it:

I created an interface

public interface CanRunSynchronouslyAndAsynchronously {
    void runSynchronously();
    void runAsynchronously(); 
}

and let my Batch classes that should support this feature implement it the following way:

public class MyBatch implements Database.Batchable<VolumeLinker__c>, Database.Stateful, 
   CanRunSynchronouslyAndAsynchronously {   ...

   public void runSynchronously() {
      this.execute(null, this.records);         
      this.finish(null);
   }

   public void runAsynchronously() {        
      Database.executeBatch(this, 200);     
   }
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.