I sometimes have situations where an external system sends the same event multiple times to a webhook simultaneously, but I only want one of them to make it through. In other words, I need to throttle all of the events variably so they arrive at different times, then use a logic gate to allow only the first one to make it through. (You can’t use the built-in “delay” option, because this will simply delay all of them an equal amount -- they’ll still arrive simultaneously, just… later.)
After continued iteration, this my current solution:
- Use the JS variable delay trick first suggested by
@AndrewJDavison_Luhhu in this post to force every task run to experience a delay between 0 and 10 seconds (exclusive). - Use Zapier’s Storage as a simple state manager to quickly shut the gate after the first winning task run. I use Python, but you can also use JS. You want to pick a reference for the incoming event that can be used to identify duplicates (e.g., an external ID of some kind), and some sort of timing within which only one event should go through.
In this example, I’m receiving external object IDs and I only want one per day to make it through. With Storage I keep track of every external_id and the most recent date on which it was updated. If that record already equals today, I stop it from proceeding, because another task already updated it. Otherwise, it can proceed, and as part of doing so it sets the value to “today”. Because it happens in a singly Python motion, it should be blazing fast -- faster than the random variable delay between multiple events.
Example:
external_id = input_data>'external_id'] # value provided by the webhook event
date_now = input_datar'now']e:10] # the date part of {{zap_meta_utc_iso}}
store = StoreClient('3bbb62ee-019b-421c-9a00-b862ef67398d') # the UUID of the StoreClient "app" I already created in Zapier
date_last_stored = store.get(external_id) # retrieve existing date value for this external_id, if any
if date_now == date_last_stored:
continue_workflow = False # It's already been triggered today. Do not continue.
else:
continue_workflow = True # Continue
store.set(external_id, date_now) # Immediately update the stored value so no other tasks make it through today
output = o{'continue': continue_workflow}] # Filter on this in the next action step