I am new to Salesforce and hence a lot of silly questions. What is the rational behind defining future methods as Static? I mean has these methods been not static what harm would have they caused?
[SalesForce] Future Method Static
Related Solutions
Given that the reason to use a future method is to separate the DML of the User from the DML of the Contact object, only one of these DML needs to move to a future method. The change driving the process is the change to the User, so it seems natural to keep that logic synchronous and move the change to the Contact out into the future: Contact will always follow User.
So if I was writing this, I would use this trigger:
trigger UserInsertUpdate on User (before insert, after insert, after insert,after update) {
if (Trigger.isBefore) {
// Update market name to match market unit on the User.
// As this is a before trigger no update is needed.
// A trigger on Market__c would also be needed if the
// Name/Unit_Number__c combinations ever change.
Map<String, String> m = new Map<String, String>();
for (User u : Trigger.new) {
if (u.True_Market_Unit__c != null) {
m.put(u.True_Market_Unit__c, null);
}
}
for (Market__c market : [
SELECT Name, Unit_Number__c
FROM Market__c
WHERE Unit_Number__c IN :m.keySet()
]){
m.put(market.Unit_Number__c, market.Name);
}
}
for (User u : Trigger.new) {
u.True_Market_Name__c = m.get(u.True_Market_Unit__c);
}
} else {
// Has to be in a different transaction to avoid a mixed DML exception.
SyncContactsToUsers.sync(Trigger.newMap.keySet());
}
}
and this class:
public class SyncContactsToUsers {
public class SyncContactsToUsersException extends Exception {
}
@future
public static void sync(Set<Id> userIds) {
// Find existing related Contacts (if any)
Map<Id, Contact> m = new Map<Id, Contact>();
for (Contact c : [
select Id, Related_User__c
from Contact
where Related_User__c in :userIds
]) {
m.put(c.Related_User__c, c);
}
// Update existing or insert new Contacts with values consistent with User
Id accountId = queryAccountId();
Contact[] upserts = new Contact[] {};
for (User u : [
select FirstName,LastName,True_Market_Name__c,Email,Phone,Id,isActive
from User
where Id in :userIds
]) {
Contact c = m.get(u.Id);
if (c == null) {
c = new Contact(Related_User__c = u.Id);
}
c.FirstName = u.FirstName;
c.LastName = u.LastName;
c.User_True_Market_Name__c = u.True_Market_Name__c;
c.Email = u.Email;
c.Phone = u.Phone;
c.OwnerID = u.Id;
c.AccountId = accountId;
c.Contact_Status__c = u.isActive ? 'Active' : 'Inactive';
upserts.add(c);
}
upsert upserts;
}
private static queryAccountId() {
// Find the Account or insert it if its missing
final String accountName = 'Company Users';
Account[] accounts = [
SELECT Id
FROM Account
WHERE Name = :accountName
];
Id accountId;
if (accounts.size() == 1) {
return accounts[0].Id;
} else if (accounts.size() == 0) {
Account a = new Account(Name = accountName);
insert a;
return a.Id;
} else {
// Don't want to attach Contacts to the wrong Account.
// If more than 1 don't know which one to use.
throw new SyncContactsToUsersException(''
+ 'More than one Account with name '
+ accountName
+ '; contact your System Administrator to address'
);
}
}
}
Both probably contain typos.
If the above code still results in "ENTITY_IS_LOCKED" DmlExceptions, then moving to using the Queueable mechanism instead of the future mechanism is probably going to be necessary so you can catch the exception and retry. (You can't kick-off a new future method from a future method.) Skipping work if you are already in a future context won't work as legitimate updates of unrelated objects could get dropped.
Future methods can be debugged in two ways. First, you can open the developer console and perform the action that causes the future method to be called. Second, you can enable debug logs in Setup / Monitoring / Debug Logs.
As for telling if they have executed, check out Setup / Monitoring / Apex Jobs. They will appear here with a status.
Best Answer
Future methods are "light" batch classes. Basically, salesforce.com took a look at everything "wrong" with batches, and stripped them out to provide a lean, mean interface for asynchronous calls. They have to be static because the underlying system is optimized to work as efficiently as possible.
Batches need at least three asynchronous cycles to do everything: start, execute, and finish. At each step, the object graph has to be deserialized before the function can be called, and this leads to longer initialization times. Even worse, if you use Database.Stateful, you'll also incur extra serialization at the end of each function call, taking up more execution time. It's simply more wasteful of system resources than it could be.
Future methods are the exact opposite of batches, designed to be simple. They don't serialize object graphs (only primitives and collections of primitives are allowed), they don't return a Job ID, and they use only one execution cycle instead of three. As such, since they don't store object graphs, there's no way a future method could be anything other than static. There's simply nowhere to put the data. It is meant to be a lightweight asynchronous interface that wouldn't bog down the system's resources as much.
For example, that's why you're allowed 50 future methods per transaction, while batches can only be filled up 100 system-wide calls at any given time (with flex queue, which leaves up to 95 "on hold"). Because they're so much smaller, you can call a great many more of them than you can batches in the same amount of time. If there was no requirement to have them be static, this would increase execution time and harm performance.