Hi, I'm using CSV export to export submissions as CSV, say, between two dates. The progress bar says 1 of 1038 records, then completes without an error; however I then have only 501 records. The rest of the records seem to have vanished.

Any help or guidance debugging this would be greatly appreciated, thanks!

Comments

alberto56 created an issue. See original summary.

jrockowitz’s picture

Status: Active » Postponed (maintainer needs more info)

Have you checked your error log? (/admin/reports/dblog)

alberto56’s picture

StatusFileSize
new347.32 KB

Nothing gets logged to the watchdog. Is there a "debug" mode I can use?

I do have a bit more info about this one.

* I have 1038 total submissions for the month of May.
* I have downloaded the submissions as CSV files several times, and the resulting file is always slightly different; it never actually has 1038 submissions though, it seems to get stuck once in a while.

$ cd ~/Downloads/
$ wc -l webform_8226*
     660 webform_8226-2 copy.csv
     562 webform_8226-2.csv
     724 webform_8226-3.csv
    1946 webform_8226-4.csv
     562 webform_8226-downloaded-automatically copy.csv
     660 webform_8226.csv
    5114 total

As you can see above, the result is inconsistent. It's not clear how to actually consistently download the exact number of submissions and have the same results every time.

alberto56’s picture

Some more information on this:

* Using a database dump from production but developing locally, this works fine.
* On Acquia cloud, this breaks, however no error message is logged.

alberto56’s picture

Title: CSV export incomplete » CSV export incomplete and inconsistent on Acquia host
jrockowitz’s picture

My best guess is that you are running out of memory.

Try decreasing the batch size (/admin/structure/webform/config/advanced).

alberto56’s picture

StatusFileSize
new103.02 KB

Thanks,

I reduced the batch size from 500 to 100 and I'm still getting the problem on Acquia cloud production (not staging). And no PHP errors.

I then set the batch size to 1, and the problem is still occurring.

I am having the same problem with Safari and Chrome.

I have opened a ticket with Acquia (number 702279) to see if they have input. I'll leave at "Postpone" until I get an answer from Acquia.

jrockowitz’s picture

The next guess is that a specific submission is causing a fatal error.

If you can export and attach your webform without any email addresses. I might be able to replicate the issue.

alberto56’s picture

a specific submission is causing a fatal error

I tried this with two completely different forms and the problem always occurs, so this is not lined to one submission.

I might be able to replicate the issue.

I cannot yet replicate it myself, this only happens on my production Acquia environment, no other environment is affected. If I manage to replicate it locally, I will package a sanitized version of the database.

Here is an interesting fact about this bug:

On my production environment where this bug occurs, on Safari on Mac, downloading an export several times in a row causes exports with different sizes, but with names which include an incremented number, as follows.

$ ls -lah *.csv
-rw-r--r--@ 1 albert  staff   219K 19 Jun 13:56 webform_50386-2.csv
-rw-r--r--@ 1 albert  staff    72K 19 Jun 13:56 webform_50386-3.csv
-rw-r--r--@ 1 albert  staff     0B 19 Jun 13:56 webform_50386-4.csv
-rw-r--r--@ 1 albert  staff    65K 19 Jun 13:57 webform_50386-5.csv
-rw-r--r--@ 1 albert  staff   333K 19 Jun 13:57 webform_50386-6.csv
-rw-r--r--@ 1 albert  staff   141K 19 Jun 13:58 webform_50386-7.csv
-rw-r--r--@ 1 albert  staff    56K 19 Jun 13:55 webform_50386.csv

On my stage environment where this bug does not occur, on Safari on Mac, downloading an export several times in a row results in there being exactly one download (which has the right number of rows): it seems that the system does not attempt to save a second version of the export if an existing version has been saved. So, no matter how many times I run the export, I get:

$ ls -lah *.csv
-rw-r--r--@ 1 albert  staff   291K 19 Jun 14:01 webform_50386.csv
jrockowitz’s picture

Some more guesses...

Could be a special character in a submission?
Could be a database issue?
Could be an issue with Acquia's temp directory not deleting the file?

alberto56’s picture

Title: CSV export incomplete and inconsistent on Acquia host » CSV export can sometimes be inconsistent (duplicate, missing records) on certain environments

Thanks @jrockowitz

I have confirmed that there is no special character in submissions or database issue, as an exact clone of the failing database works on another environment.

However, I will look into the /tmp directory issue, thanks for that idea!

Here is another interesting fact:

On an environment that works, I can download 972 submissions, and end up with a file with 973 lines (which is expected):

$ wc -l ~/Downloads/*.csv
973 /Users/albert/Downloads/webform_50386.csv

On an environment which does not work, if you download the same file often enough, you can end up with a file having number of lines which is _higher_ than actual number of submissions, in this case webform_50386-9.csv has 1032 lines but there are only a total of 972 submissions:

$ wc -l ~/Downloads/*.csv
442 /Users/albert/Downloads/webform_50386-2.csv
125 /Users/albert/Downloads/webform_50386-3.csv
809 /Users/albert/Downloads/webform_50386-4.csv
948 /Users/albert/Downloads/webform_50386-5.csv
402 /Users/albert/Downloads/webform_50386-6.csv
520 /Users/albert/Downloads/webform_50386-7.csv
361 /Users/albert/Downloads/webform_50386-8.csv
1032 /Users/albert/Downloads/webform_50386-9.csv
168 /Users/albert/Downloads/webform_50386.csv
973 /Users/albert/Downloads/uncorrupted-data-webform_50386.csv
5780 total

In this case the corrupted /Users/albert/Downloads/webform_50386-9.csv has _more_ lines than /Users/albert/Downloads/uncorrupted-data-webform_50386.csv, which is the uncorrupted export.

I checked the diff between the corrupted and uncorrupted exports, and it turns out several records are missing in the corrupted export, and other records are duplicated, which accounts for the fact that the corrupted file is larger than the uncorrupted file.

alberto56’s picture

Here are the contents of my /tmp directory on Acquia:

On the broken environment:

$ ls -lah /tmp|grep webform
-rw-r--r--  1 me       me       9.2K Apr 30 18:25 webform_a3zPX8
-rw-------  1 me       me       2.3M Apr 30 20:25 webform_ecqX0Q
-rw-r--r--  1 me       me        79K May 21 16:35 webform_eRvki6
-rw-r--r--  1 me       me       8.2K May  3 19:17 webform_zzZs8R

On the working environment:

$ls -lah /tmp|grep webform

(it is empty)

I deleted all webform_* files (which were all old files from an old Drupal 7 environment) from the /tmp directory in the broken environment, and, still, getting the same behaviour.

alberto56’s picture

Here is some more information on this: Acquia seems to store different production sites on the same servers, so I have another site I manage, this one a Drupal 7 site, on the same production server as the affected Drupal 8 site.

I also have Webform D7 on that site, and I am experiencing similar behavior when downloading exported Webform Submissions: downloading a submission on the Drupal 7 on that server systematically results in zero-byte downloads, but on the staging environment of that Drupal 7 site everything works as expected.

I am still waiting for a response from Acquia on this and will update this issue accordingly.

jrockowitz’s picture

It sounds like Acquia is having issues with the tmp file directory.

I would expect if you deleted all the webform_* temp files and created a new export it should work.

The \Drupal\webform\Controller\WebformResultsExportController::downloadFile method deletes the temp CSV. You might want to comment out $response->deleteFileAfterSend(TRUE); and see what is left the /tmp directory.

BTW, have tried using the drush webform-export command.

alberto56’s picture

Status: Postponed (maintainer needs more info) » Closed (works as designed)

@jrockowitz thanks to your help, I have found the issue:

It sounds like Acquia is having issues with the tmp file directory.

is exactly right. Changing the /tmp directory to something else completely fixed this issue.

Here is how I found this:

drush webform-export worked perfectly. However, deleting "webform_*" files from the /tmp directory did not fix the issue.

I then changed the \Drupal\webform\Controller\WebformResultsExportController::downloadFile to this:

  public function downloadFile($file_path, $download = TRUE) {
    clearstatcache(TRUE, $file_path);
    $response = new BinaryFileResponse($file_path, 200, [], FALSE, $download ? 'attachment' : 'inline');
    // $response->deleteFileAfterSend(TRUE);
    \Drupal::logger('WFTEST')->notice('Serving file ' . $file_path);
    return $response;
  }

just to see what happens.

With that code in place, I deleted everything in my /tmp folder and my downloads folder, then exported a webform with 972 submissions, then I performed a download a first time.

This created a file with 801 lines in my /tmp folder:

$ wc -l webform_50386.csv
801 webform_50386.csv

I can then repeatedly download this file by clicking "Download the file here" (because it is not deleted after it is downloaded, as per my above changes).

The result is all over the map:

wc -l webform_*
     473 webform_50386-2.csv
     473 webform_50386-3.csv
     473 webform_50386-4.csv
    1201 webform_50386-5.csv
     473 webform_50386-6.csv
    1401 webform_50386-7.csv
     901 webform_50386.csv
    5395 total

This told me that, definitely there is a problem with /tmp folder.

Because this issue has nothing to do with Webform, I'll close it.

Thanks again for your kind assistance!

alberto56’s picture

Category: Bug report » Support request
jrockowitz’s picture

@alberto56 What version of PHP are you running on Acquia?

jrockowitz’s picture

I think you need to change your temp directory.

@see https://docs.acquia.com/en/stable/acquia-cloud/manage/files/broken/

alberto56’s picture

Thanks for the resource. I'm using php 7.2. And, yes, changing the /tmp directory makes everything work perfectly!

alberto56’s picture

In fact #2221651: Make temporary export file path configurable is the exact issue I am having.

alberto56’s picture

Title: CSV export can sometimes be inconsistent (duplicate, missing records) on certain environments » Webform assumes the /tmp directory is always the available, but if there are multiple servers, each may have its own /tmp directory

This got me thinking: as a lot of webservers are moving toward multi-node setups, multiple containers such as Kubernetes, and so on, might it benefit Webform to no longer assume that /tmp is always accessible and the same between requests? See also https://stackoverflow.com/questions/50955591

alberto56’s picture

Title: Webform assumes the /tmp directory is always the available, but if there are multiple servers, each may have its own /tmp directory » Webform assumes the /tmp directory is always the same, but if there are multiple servers, each may have its own /tmp directory
jrockowitz’s picture

I can't see having webform write temp files to the /sites/files directory. If the files directory is being replicated it would create performance issues during the batch export. My main client's load balancers keeps a returning user on the same server.

Acquia's connector should add a warning to Drupal's status report.

alberto56’s picture

Hi, Acquia has gotten back to me, suggesting I use the technique at #2221651: Make temporary export file path configurable. On this page, they say:

The Webform module can have issues similar to what you may experience with Plupload. Versions 7.x-4.x or greater and 8.x-5.x or greater of the Webform module include the webform_export_path variable, which (depending on your Drupal version) you can set in your settings.php file

However, that functionality seems to have been removed in commit c938264 of Webform:

$ git diff 17a8566 c938264 | grep webform_export_path --before-context=5 --after-context=5
-
-/**
- * Returns a temporary export filename.
- */
-function _webform_export_tempname() {
-  return drupal_tempnam(variable_get('webform_export_path', 'temporary://'), 'webform_');
-}
-
-/**
- * Generate a Excel-readable CSV file containing all submissions for a Webform.
- *
$ git diff 17a8566 c938264 | grep _webform_export_tempname --before-context=5 --after-context=5
-
-  function post_process(&$results) {
-    // Our download file is currently a single XML sheet file. We need to add
-    // the peripheral XML files to make this into a XLSX directory, then zip it.
-    $file_uri = $results['file_name'];
-    $zip_uri = _webform_export_tempname();
-
-    // ZipArchive does not support stream wrappers, convert to filesystem path.
-    $zip_filepath = drupal_realpath($zip_uri);
-    $file_filepath = drupal_realpath($file_uri);
-    $zip = new ZipArchive;
--
--
-  // Determine an appropriate batch size based on the form and server specs.
-  if (!isset($options['range']['batch_size'])) {
-    $options['range']['batch_size'] = webform_export_batch_size($node);
-  }
-
-  $options['file_name'] = _webform_export_tempname();
-
-  // Set up a batch to export the results.
-  $batch = webform_results_export_batch($node, $format, $options);
-  batch_set($batch);
-}
--
--
-}
-
-/**
- * Returns a temporary export filename.
- */
-function _webform_export_tempname() {
-  return drupal_tempnam(variable_get('webform_export_path', 'temporary://'), 'webform_');
-}
-
-/**
- * Generate a Excel-readable CSV file containing all submissions for a Webform.
--
--
-  $options['range'] += $defaults['range'];
-
-  // Open a new Webform exporter object.
-  $exporter = webform_export_create_handler($format, $options);
-
-  $file_name = _webform_export_tempname();
-  $handle = fopen($file_name, 'w');
-  if (!$handle) {
-    return;
-  }
-

I informed Acquia of your suggestion to always direct same-source traffic to the same server, however my understanding is that as of right now all Acquia "enterprise" users having more than one webserver will be unable to export any submission data.

jrockowitz’s picture

Status: Closed (works as designed) » Needs review
StatusFileSize
new4.56 KB

Here is my first attempt at a patch.

jrockowitz’s picture

StatusFileSize
new7.61 KB

The attached patch adds directory validation and configuration to the custom temp directory.

jrockowitz’s picture

StatusFileSize
new648 bytes
new7.64 KB
alberto56’s picture

Status: Needs review » Needs work

Thanks, much appreciated!

Applying this patch and running drush updb -y works fine.

Changing the settings via the GUI at /admin/structure/webform/config/exporters and exporting the settings yields:

--- a/drupal-server/config/webform.settings.yml
+++ b/drupal-server/config/webform.settings.yml
@@ -82,7 +82,7 @@ export:
   delimiter: ','
   excel: false
   excluded_exporters: {  }
-  file_name: 'submission-[webform_submission:serial]'
+  temp_directory: /this/directory/exists
 batch:
   default_batch_export_size: 100
   default_batch_update_size: 100

(I'm not sure why it's removing "file_name" here... maybe that's unrelated?)

However I ran into the following problems:

(1) if the directory does not exist we get a fatal error:

The website encountered an unexpected error. Please try again later.
Error: Call to a member function mkdir() on null in Drupal\webform\Form\AdminConfig\WebformAdminConfigExportersForm->validateForm() (line 128 of modules/webform/src/Form/AdminConfig/WebformAdminConfigExportersForm.php).
Drupal\webform\Form\AdminConfig\WebformAdminConfigExportersForm->validateForm(Array, Object)
call_user_func_array(Array, Array) (Line: 83)

(2) if the directory exists but does not have the correct permissions I get:

The website encountered an unexpected error. Please try again later.
Error: Call to a member function chmod() on null in Drupal\webform\Form\AdminConfig\WebformAdminConfigExportersForm->validateForm() (line 131 of modules/webform/src/Form/AdminConfig/WebformAdminConfigExportersForm.php).

(3) if the directory does exist and has the correct permissions (777 in my case) and I set it using the GUI, the system still uses "/tmp", not the new directory.

jrockowitz’s picture

Status: Needs work » Needs review
StatusFileSize
new683 bytes
new7.68 KB

Attached patch fixes the errors.

The 'file_name: 'submission-[webform_submission:serial]'' change can be ignored.

alberto56’s picture

Status: Needs review » Needs work

No longer getting fatal errors, however the system is still, in my case, using the /tmp directory.

I noticed that you are making the following change to ./src/WebformSubmissionExporter.php:

   public function getFileTempDirectory() {
-    return file_directory_temp();
+    return $this->configFactory->get('webform.settings')->get('export.temp_directory') ?: file_directory_temp();
   }

However there is another file which contains getFileTempDirectory(), which has not been changed: ./src/Plugin/WebformExporterBase.php

  /**
   * {@inheritdoc}
   */
  public function getFileTempDirectory() {
    return file_directory_temp();
  }

Perhaps making the same change to the above method will cause the configured temporary directory to be used.

Would it also be useful to add some more context to the help text, otherwise users might not understand why we're not just using the /tmp directory. Instead of

A local file system path where temporary export files will be stored. This directory should not be accessible over the web.

something like:

A local file system path where temporary export files will be stored. This directory should be persistent between requests and should not be accessible over the web.

jrockowitz’s picture

Status: Needs work » Needs review
StatusFileSize
new8.25 KB
new1.31 KB

Good catch! and thanks for the editorial suggestion.

alberto56’s picture

Status: Needs review » Reviewed & tested by the community

This works perfectly in my local tests, thanks! I will deploy this to the production site tomorrow and have more input.

  • jrockowitz committed 3479d1c on 8.x-5.x
    Issue #2980276 by jrockowitz, alberto56: Webform assumes the /tmp...
jrockowitz’s picture

Status: Reviewed & tested by the community » Fixed
alberto56’s picture

Thanks for taking this on @jrockowitz, I think this will help all Acquia users who are exporting submissions.

I just deployed this to my production and it works exactly as expected: if the config is not set, the default /tmp folder is used, and if the config is set, the custom directory is used.

jrockowitz’s picture

@alberto56 Can you please write a very brief change record? Should just be two sentences and can link to the Acquia article.

You can cut-n-paste info from this ticket and #2221651: Make temporary export file path configurable.

alberto56’s picture

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.

alberto56’s picture

krith_18’s picture

Hi,

Sorry for reopening this ticket.

I face the exact same issue. My codebase is hosted in acquia cloud enterprise and i face the same issue in downloading the webform report.
I went through the patch and it seems like its already incorporated in the webform codebase. I manually compared the patch file and noticed that in src/Form/AdminConfig/WebformAdminConfigExportersForm.php - in this file $config->save(); is missing in 155 line whereas in the patch (https://www.drupal.org/files/issues/2018-06-26/2980276-31.patch) it is there. Is there any reason for that code to be removed? This is my first project using webform.

Do help as this happens in production only. I have created a support ticket in acquia and they gave this patch link.

Thank you in advance!

Regards,
Krithika

baikho’s picture

Hi @krith_18,

Not sure if it solves your problem, but it did for me; can you make sure that you specify the tmp file directory as follows:

$settings['file_temp_path'] = "/mnt/gfs/{$_ENV['AH_SITE_GROUP']}.
{$_ENV['AH_SITE_ENVIRONMENT']}/tmp";

See relevant AC documentation: https://docs.acquia.com/acquia-cloud/manage/files/broken/#setting-the-di...

Note that there is a significant difference between Drupal 8/9 and 8.7.x

krith_18’s picture

Hi @baikho,

Thank you so much!
I will change in settings.php and will deploy to prod and will check.
Once deployed , i will let you know if that works.
Thanks much!

dasginganinja’s picture

In case anybody needed to override this in settings.local.php here is the code:

$config['webform.settings']['export']['temp_directory'] = '/files/tmp-shared-directory';