TransWikia.com

Retain Guzzle Session During Batch Operations

Drupal Answers Asked by tyler.frankenstein on January 2, 2022

On a Drupal 7 site, I am using the Batch API to perform operations on many entities, one at a time. During a typical operation, the D7 site uses Guzzle to make a POST call to a Drupal 8 site. The D7 Batch callback looks like this:

function example_operation($foo, &$context) {

  // Login to Drupal 8.
  // ...

  // Make POST call to Drupal 8.
  // ...

  // Logout from Drupal 8.
  // ...

}

The D7 client uses a Guzzle client and cookie jar to authenticate with the D8 server (REST+cookies), with no issues. Great!

Now imagine running this on 100K+ entities, that’s an awful lot of logging in and out unnecessarily, wasting a whole bunch of time and resources. So I figure, let’s login once on the first operation, retain that session for each operation, then logout when finished. Sounds reasonable.

I thought I’d use D7 Batch API’s $context['results'] array to hang onto the cookie jar and D8 rest tokens, that way each operation would have access to them, no problem, or so I thought. Take a look at this attempt in the D7 Batch callbacks:

function example_operation($foo, &$context) {

  $jar = NULL;
  $csrfToken = NULL;

  // Login to Drupal 8 (first time only)
  if (!isset($context['results']['jar'])) {

    // Login to Drupal 8.
    // ...

    // Set aside cookie jar and tokens.
    $context['results']['jar'] = $jar;
    $context['results']['csrf_token'] = $csrfToken;
    $context['results']['logout_token'] = $logoutToken;

  }
  else {

    // We've already logged in, grab the cookie jar and token.
    $jar = $context['results']['jar'];
    $csrfToken = $context['results']['csrf_token'];

  }

  // Make POST call to Drupal 8 (using cookie jar and token).
  // ...

}

function example_finished($success, $results, $operations) {

  // Pull out cookie jar and tokens.
  $jar = $results['jar'];
  $csrfToken = $results['csrf_token'];
  $logoutToken = $results['logout_token'];

  // Logout from Drupal 8 (using cookie jar and tokens)
  // ...

}

This approach works fine on the first operation only. Then on the second operation, the tokens are available in $context['results'] as expected, but the cookie jar always comes through as a __PHP_Incomplete_Class Object, and then if I try using it with the Guzzle client a cookies must be an instance of GuzzleHttpCookieCookieJarInterface is thrown.

How do you retain a Guzzle session between batch operations in Drupal 7?

  • Perhaps $context['results'] cannot contain "complex" class/objects like a Guzzle cookie jar
  • I tried using the cookies request option when instantiating the Guzzle client, but that breaks any authenticated POST calls (including the first operation)
  • Maybe the way D7’s batch http requests work, it starts confusing the client/cookies/etc

One Answer

Between two batch runs, the data is saved in the database serialized. Before the second batch run, the data is taken from the database and unserialized. __PHP_Incomplete_Class Object tell us that, at the moment the data is unserializes, no GuzzleHttpCookieCookieJarInterface class is available, and objects of that class cannot be unserialized.

To retain a Guzzle session between batch runs, you can save the data as array.

$context['results']['jar'] = $jar->toArray();

To get back the data, you can then use the following code.

$jar = CookieJar::fromArray($context['results']['jar'], 'domain.com');

If you save an object in $context, as in your case now, it would be available through all iterations at one batch run, but at the next run, an error is thrown.
If you still prefer to keep objects during iterations instead of arrays, to avoid errors you should check if $context['results']['jar'] is an instance of GuzzleHttpCookieCookieJarInterface.

Answered by Eugene Bocharov on January 2, 2022

Add your own answers!

Ask a Question

Get help from others!

© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP