Automatically unlock imports with Entity Synchronization

Body

The Entity Synchronization Drupal module supports managed, regular imports of lists of recently created or updated entities from remote systems. The imports can be run in a number of different ways: via cron, as items in the queue, using Drush, or manually in the admin Sync UI. To prevent an import from running multiple times in parallel - which could potentially have undesirable consequences, the module provides a state manager that locks the import when it starts and it unlocks it when it finishes.

Most errors during imports are caught and logged; however, there are certain types of fatal errors that may cause the import to abruptly stop execution. Such errors are mostly caused by involuntary infrastructure-related disruptions e.g. hardware failure, kernel panic, cluster network partitioning events, process termination due to the server running out of resources etc. There are some edge cases of software errors that will also not be caught by the Entity Synchronization import manager which I will not describe here.

When such errors happen during an import, it gets stuck in the locked state. When the next time comes for the import to run, it will stop before starting; that's the expected behavior because the import could be locked because it is currently running in parallel by another process. Until now, resolving this would require manual intervention by a developer:

# Manually unlocking an operation.
drush esync-suo my_import import_list

While it is important for a developer to look into the cause of the failure so that it does not happen again, waiting for manual intervention when eventually somebody notices may not be an option. Imagine, for example, an online store where products and stock quantities stop being imported from a remote ERP system - and therefore stop being sold. I recently added support for automatically unlocking imports managed by Entity Synchronization. The new auto_unlock property can be set to a time interval, in seconds, after which the import will be automatically unlocked.

Let's say that we have an import scheduled every 15 minutes using the Ultimate Cron module. It imports up to 200 entities on each run and the expected duration is 2-5 minutes. It is important to set auto_unlock to a value much higher than the normal duration of the import so that we can be certain that if the operation is still locked after that time interval, it cannot be that the operation is still running and we can have the certainty that something went wrong and the operation got stuck in the locked state. In the case above, I would set the value to 30 minutes. Here is how this would look like:

# entity_sync.operation_type.my_import.yml
# Only relevant properties are shown.
operations:
   import_list:
     state:
       manager: entity_sync
       lock: true
       auto_unlock: 1800

That's it! When the next import runs less than 30 minutes after the last one - the one that got stuck in the locked state - a warning message will be logged and the operation will be aborted. The run after that one though will automatically unlock the state and run the operation as usual. Remember to monitor for such incidents and investigate them!