Problem/Motivation
Submissions exports have the following format 'dir/webfrom/[webform_id].ext or ..., the filename is the save on every export.
\Drupal\webform\Plugin\WebformExporterBase::getBaseFileName
/**
* {@inheritdoc}
*/
public function getBaseFileName() {
$webform = $this->getWebform();
$source_entity = $this->getSourceEntity();
if ($source_entity) {
return $webform->id() . '.' . $source_entity->getEntityTypeId() . '.' . $source_entity->id();
}
else {
return $webform->id();
}
}
On sites with several web nodes sharing the export directory over NFS, each batch request can hit a different node. When one node deletes and recreates the file, another node may still hold the old file handle in its NFS client cache, so `fopen()` fails:
Warning: fopen(/app/tmp/webform/my_form.csv): Failed to open stream: Stale file handle in
Drupal\webform\Plugin\WebformExporter\TabularBaseWebformExporter->createExport()
TypeError: fputcsv(): Argument #1 ($stream) must be of type resource, false given in fputcsv()
(line 116 of src/Plugin/WebformExporter/DelimitedWebformExporter.php).
The shared file name also makes two concurrent exports of the same webform write to (and delete) the same file.
Steps to reproduce
- Run Drupal on 2+ web nodes with the Webform export temp directory on a shared NFS mount.
- Export the results of a webform with enough submissions to require a batch, then download the file.
- Export the same webform again right away. Some batch requests fail with the error above on the node that cached the deleted file.
Proposed resolution
Use a token for each batch to avoid filename collisions between batch executions.
Remaining tasks
TBD.
User interface changes
TBD.
API changes
TBD.
Data model changes
TBD.
Issue fork webform-3632332
Show commands
Start within a Git clone of the project using the version control instructions.
Or, if you do not have SSH keys set up on git.drupalcode.org:
Comments
Comment #3
eduardo morales albertiCreated MR:
Generate a token prefix:
The token is only internal; it will never download the file with it:
Added a custom method openFileHandle, to catch the file when it is not available
Delete orphan export files using cron: