When Drupal's batch meets drush

While Drush is a nice and handy CLI tool that especially eases shell and cron integration in advanced *X setups, Drupal’s so-called batch API was once designed to work around problems resulting from the lack of a full root access which was widespread standard with web hosting those days (and often still is).

This can become a problem once you want to build advanced environments with sophisticated workflows. Today’s example is (otherwise great) pathauto module.

Problem

Pathauto origins from a time where Drush was little noticed and, as said above, shell access was “expensive”. Thus, it takes Drupal’s batch API to the rescue. Unfortunately it does this so deep, that even a database operation has been put directly into the batch processing API, instead of separating core functionality and API overhead from each other. As a consequence, there is no chance to easily trigger generation of missing aliases with one command (while you can trigger it with one click from the GUI backend).

Existing workarounds include fake-launching a batch job via drush, some suggest a drush eval construct including DB queries. Of course, some also suggest writing a module, just for this task. Which isn’t easy either, since there is still no real way to hook into the background processes.

In my special case, I cannot even use pathauto’s Rules integration, because a sub-domain multisite structure with (partly) shared tables is involved, and the “url_alias” table is no candidate for sharing due to its all-in-one structure. (My multi-site only shares strictly session and user related tables.) Praise Rules’ custom PHP action as a remedy, again:

Workaround

My cron runs are triggered through Drush anyway, a Drush core capability. This means, they are timeout-safe out of the box and it does not matter if there are 10 or 1000 new users to alias at a time. Thus, I set up a rule reacting on cron runs, to execute a code snippet from Pathauto’s user_pathauto_bulk_update_batch_process() which is hopefully generic enough to live until the end of Drupal 7’s lifecycle: