7

I have multiple processes (teams of users) that need to mutually exlusive work on the sames data records in Salesforce.

Is there a way to simulate a kind of Mutex or Semaphore in Salesfore (e.g. with programatic sharing) ? Languages similar to Apex like Java often have own language constructs like synchronised to solve that.

Has anyone implemented such a locking mechanism and is willing to share his experience?

6
  • 1
    possible duplicate of SOQL Record Locking (FOR UPDATE)
    – eyescream
    Commented Jan 10, 2014 at 8:55
  • Sorry, no duplicate as FOR UPDATE locks are not long lasting (weeks of locking) and cannot be aquired and released programatically but only by executing the SOQL itsself. Commented Jan 10, 2014 at 10:05
  • 1
    I thought it was transaction-related, not long lasting. For short-term locks - FOR UPDATE. Longer locks - have a look at approval processes. Or create some flag on record (name of group that's allowed? Concatenated string of role names?) and validation rule that'll prevent updates (trigger might be better- val. rules don't fire when you delete the record).
    – eyescream
    Commented Jan 10, 2014 at 10:15
  • I don't see why you couldn't use record sharing with public read-only OWD sharing settings, but it would probably take some planning to get it right. Especially since any Apex code written as "without sharing" would ignore sharing settings.
    – pchittum
    Commented Jan 10, 2014 at 10:45
  • 1
    Transformed my comment into an answer.
    – pchittum
    Commented Jan 10, 2014 at 12:10

2 Answers 2

8

My tuppence worth, very much late to the party.

We had a need to do this as well. Our customers needed to expose wide sets of data to their users and let them select the sub-set they wanted to process. Thus we couldn't use Sharing Rules to define the scope and needed to provide some form of synchronization/guaranteed single threading in order to check for non-overlapping sub-set processing requests.

A little-known feature in Salesforce is that it guarantees that there is only ever a single batch process instance, implementing the Database.Batchable interface, executing the start method at any one time in a given org. This is in the Salesforce documentation and reproduced here:

Only one batch Apex job's start method can run at a time in an org. Batch jobs that haven’t started yet remain in the queue until they're started. Note that this limit doesn’t cause any batch job to fail and execute methods of batch Apex jobs still run in parallel if more than one job is running

You can, therefore, rely on this as a type of "synchronized block", but only in rather specific cases. Remember, there are limits on the number of batch executions permitted concurrently, in the queue (batch queue and Apex Flex Queue) and per-org-per-day. See the "Batch Apex Governor Limits" sub-section in the documentation page I already linked to.

We wrote supporting Apex code that allowed the various batch instances to know which other instances are still running/queued and what specific data sets they are to process (we did this by describing the data sets in custom objects in the database and linking these to the relevant job IDs so we could tell which data is still relevant in case of unexpected termination of batches leaving data behind).

5

The whole purpose of the sharing model is to ensure the correct users access the right records at the right time. This is an expansive subject and understanding this well is one of the critical pieces to getting the most out of the platform. Not understanding it, you risk reinventing the wheel programmatically, and inevitably causing yourself and others headaches down the line.

First of all sharing works in conjunction with your profile CRUD settings. So without the correct profile setting, you won't access the object/entity in the first place. Let's say our user has create-read-edit-delete access on their profile.

Sharing begins with record ownership. Unless you are the record owner, you cannot delete, share, or transfer ownership of the record. So even if your CRUD profile setting says "Delete", unless you are the owner, you can't delete anyway.

Next your organization-wide default (OWD) sharing settings for an object. This sets the basic access for all other non-owner users. The most access (and default for custom objects) is public read/write, which gives all users the ability to read and edit all records of that entity, but doesn't include delete. Next is public read-only, which gives all users the ability to read records, but no edit perms. Finally there is private which means that unless you are the owner...or you are given access through some other means (wait for it...) you have no access to records.

OWD's are the only way to remove access to records. Everything else that follows is about giving access to records.

Next we have roles. Roles are a hierarchical scheme that allow some users to inherit access to records based on other users below them in the hierarchy. If I sit above a user in the hierarchy, I will inherit that user's access to a record. So if a user below me is an owner...I have ownership permissions. If a user below me has read-only access...I have read-only access...etc.

Territories also exist similarly to roles but have widespread ramifications and are only turned on in some orgs. The fundamental difference is that roles are single-inheritance and that territories allow multiple inheritance. Until Spring 14, once territories are turned on, they cannot be turned off again.

Next we have sharing rules whereby we can share a record with a role, a role and all of the roles below that role (roles and subordinates), or a public group (different from a Chatter group).

Sharing can also be performed one-off by a user.

Sharing can also be performed with Apex in Apex managed sharing.

Finally, no matter your record/sharing access, field security will still be enforced for the user's profile. So whether or not I'm the owner, if my profile denies me access to a certain field, I can't access that field.

I have not had to go through the process first-hand of setting these things up in an org, but I can say that orgs that do not plan this out typically have headaches and problems. But this is the fundamental architecture in the platform to ensure user-to-record access and security.

Here are some links to resources to read up on these:

Overview of Security wiki: https://trailhead.salesforce.com/en/modules/data_security

Sharing Architecture whitepaper: https://developer.salesforce.com/docs/atlas.en-us.dat.meta/dat/dat_intro.htm

Apex managed sharing wiki: https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_bulk_sharing_creating_with_apex.htm

More on Apex Managed sharing from the Apex dev guide: http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_bulk_sharing_understanding.htm

Hands-On Training for Troubleshooting Record Access from DF13: http://youtu.be/KfcNn3IEF4A

2
  • Great explanation if the whole topic. Thank you! If two groups of people as in my case in general have access to Object a but should not access a single record of that type at the same time I see Claiming Ownership as the only means. Commented Jan 10, 2014 at 12:51
  • That's really the purpose. OWD=public read only or private (if you want it invisible to others) in that case, then use workflow or Apex managed sharing to move ownership of the record. For Leads, Cases, and all custom objects, you can also make a Queue an owner if there needs to be a pool of people accessing a record...when I have time I might go back and annotate my answer to say as much. :-)
    – pchittum
    Commented Jan 10, 2014 at 13:37

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .