+ Start a Discussion
David81David81 

@future loop troubles

I'm hoping some genius out there can help me figure this one out.

 

We just implementing some geocoding code to get tie into the Yahoo Placefinder API. The code is designed to run on record inserts and updates if the data used for geocoding has changed. Currently I have a workflow run and field update in place to set a field called "GeoCode Status" to "Needs Update" when the criteria changes and the apex trigger only calls for geocoding when the "GeoCode Status" field has changed to this value.

 

This works great and fails gracefully if info cannot be retrieved.

 

One problem has arisen, though, due to an AppExchange app called DupeBlocker from CRMFusion. For those that are unfamiliar, this is a duplicate management/prevention app. It has one feature that auto-merges records based on criteria we define. Enter the issue....

 

  1. The dupe checks are all done in @future annotated methods.
  2. The auto-merges can potentially update address fields.
  3. Updates to address fields trigger geocoding.
  4. Geocoding, being doing through a callout, must be in an @future annotated method.
  5. @future methods cannot trigger other @future methods.

This only comes up when an auto-merge happens, but I'd like to figure out some what of getting around this if possible.

 

Thanks in advance,

 

David

 

Ritesh AswaneyRitesh Aswaney

Right, so we only want to invoke your geotagging future method if it is being invoked from a non future context.

There isn't a straightforward way of doing this, but I think there may be a work around.

 

The Salesforce API provides a Limits class which gives you the various resource limits available in a context. These limits differ for future methods. Perhaps we could use this to control when to invoke your geotagging code.

 

The SOQL Query Limit for 'Normal' Contexts is 100, whereas for a future context it is 200. 

 

So

if (Limits.getLimitQueries() != 200)

{

//Invoke your future method for geo tagging

}

 

 

http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_methods_system_limits.htm

 

http://www.salesforce.com/us/developer/docs/apexcode/Content/apex_gov_limits.htm

David81David81

Ritesh,

 

That may just work. I'll have to give it a try.

 

I'd then just have to schedule a batch to run every hour to pick up any records that were "left behind" and geo code those...

 

The only issue I can see with that is the dynamic nature of the limits. A new release could easily break that workaround but it may do for now.

Ritesh AswaneyRitesh Aswaney

There's always CustomSettings for externalising the actual value of the Query Limit. It would be quite interesting to see if that solves your problem :)

Cory CowgillCory Cowgill

If Ritesh's suggestion doesn't work another option may be to strictly encapsulate the GeoCoding logic strictly inside a Batch Apex job and use the Database.AllowCallout{} block. Schedule that to run every hour just like you were thinking above.

 

In your Batch Apex select statement, just pull the accounts with your GeoCode flag set to "Ready for GeoTagging" or whatever.

 

Then you can get rid of the @future logic which is conflicting with your DupeChecker Application altogether and keep the geolocation code in one place.

 

Just another slightly different option which you seem to be onto somewhat already.

 

 

 

VPrakashVPrakash

David,

 

this link @Future will be helpful to solve your issue.

David81David81

Thanks Cory,

 

I'd actually been debating relegating this to a scheduled batch entirely but chose not to do this due the possibility that geocoding data may be needed soon after updating/inserting the records.

 

I debating the feasibility of dynamically scheduling the batch to run shortly after being triggered from another future method. I've already got the batch class written to deal with situations where geocoding is needed on more than 10 records, so it should be pretty easy to do the check for the future context and schedule a batch as needed. Thoughts?

David81David81

Looks like that didn't solve it. Just got another exception today from future calling future. The trigger code is wrapped in an if statement that checks the query limit but it still executed for some reason.

 

Unfortunately, I haven't been able to replicate this issue on demand so I don't have any full logs available.

 

Very frustrating.

David81David81

Ok,

 

So I was finally able to replicate this issue consisently and get some logs. It seems that Limits.getLimitQueries() always returns 100 in every invocation of my trigger.

 

Perhaps this will only return 200 when called from within the future method itself?

 

If so, am I just SOL then?

David81David81

Partial solution in place. I'm now just catching any AsyncException from the trigger and scheduling a batch job to run in 5 minutes to GeoCode the records that need updated.

 

My problem comes from removing the job from the queue after it's completed. If I query the CronTrigger table it says that the State of the job is "DELETED" but it still appears in the queue. The only way to remove it is to manually do so through the UI (not an option) or to issue a system.abortJob on the ID of the CronTrigger. That's, in itself is easy enough, but I somehow need to get that ID in the finish method of my batch job.Since the "Name" field on CronTrigger is not available, I can't just query the table for the job in question.

 

I can get the ID in my trigger context, but I have no idea how to pass it along to the batch job that has been scheduled...

 

Any thoughts on this one?

 

EDIT: Solution found after scouring the boards for some somewhat related topics. Turns out I just needed to add

 

system.abortJob(sc.getTriggerId());

 

to the end of my execute method in the schedulable class. So far so good.