In the processitem() method of my custom QueueWorker class (to be handled by cron) I have the following line of code.
$store = \Drupal::service('tempstore.shared')->get('fjmodule.urls');
This worked fine in Drupal 8.x and also in Drupal 9.0 and Drupal 9.1
Since the upgrade to Drupal 9.2 it craches with the following error:
Type:cron
Date:Thursday, November 18, 2021 - 17:32
User:Anonymous (not verified)
Message:RuntimeException: Failed to start the session because headers have already been sent by "C:\Users\frans\Sites\devdesktop\mz\core\modules\big_pipe\src\Render\BigPipe.php" at line 264. in Symfony\Component\HttpFoundation\Session\Storage\NativeSessionStorage->start() (line 152 of C:\Users\frans\Sites\devdesktop\mz\vendor\symfony\http-foundation\Session\Storage\NativeSessionStorage.php)

Comments

fxa created an issue. See original summary.

cilefen’s picture

Component: cron system » other
Status: Active » Postponed (maintainer needs more info)
Issue tags: -Drupal 9.2 Queueworker 'tempstore' service

It is almost impossible that extracting that core service and calling a method on it would issue an HTTP header early. That service is used in several places in Drupal Core but they are not broken. It is more likely that custom code is doing so, but there are less likely possibilities. It is certainly impossible for us to provide support here, if there is custom code involved, without being shown all the code.

larowlan’s picture

fxa’s picture

Some more information.
I configured cron to run every hour.
The problem occurs only when a user is logged on and the cron task runs because the last cron run was more then an hour old.
When I trigger the cron task from the admin menu...there is no problem.
Also when there is no user logged on and cron runs... there is no problem.

This is the code.
<?php

namespace Drupal\fjmodule\Plugin\QueueWorker;

use Drupal\Core\Queue\QueueWorkerBase;

/**
* Processes tasks for example module.
*
* @QueueWorker(
* id = "url_queue",
* title = @Translation("Example: Queue worker"),
* cron = {"time" = 5}
* )
*/
class UrlQueue extends QueueWorkerBase {

/**
* {@inheritdoc}
*/
public function processItem($item) {
$url = $item->url;
\Drupal::logger('fjmodule_queue_cron')->notice("Start ".$url);
$store = \Drupal::service('tempstore.shared')->get('fjmodule.urls');
\Drupal::logger('fjmodule_queue_cron')->notice("End ".$url);
$info = [];
$info['time_last_verified'] = REQUEST_TIME;
$info['result'] = $verificationResult;
// The key can only be 128 Chars.
$store->set(substr($url, 0, 128), $info);
return;
}
}

This is an extract of the recent log messages

cron 11/20/2021 - 18:49 RuntimeException: Failed to start the session because… Anonymous (not verified)
fjmodule_queue_cron 11/20/2021 - 18:49 Start https://www.google.be/maps/place/ALDI/@50.7822688… Anonymous (not verified)
cron 11/20/2021 - 18:49 RuntimeException: Failed to start the session because… Anonymous (not verified)
fjmodule_queue_cron 11/20/2021 - 18:49 Start https://www.google.be/maps/place/Lidl/@50.779345,… Anonymous (not verified)
cron 11/20/2021 - 18:49 RuntimeException: Failed to start the session because… Anonymous (not verified)
fjmodule_queue_cron 11/20/2021 - 18:49 Start https://www.google.be/maps/place/Albert+Heijn/@50… Anonymous (not verified)

larowlan’s picture

Can you describe the intention of the code so we could perhaps suggest an alternative approach

Temp store relies on a session I think

fxa’s picture

I want to test that a series of url's used somewhere on the site are still valid.
If they are... I store the last verification time in the tempstore.

larowlan’s picture

I don't see any validation taking place there, so I assume this is just some of the code.

Any reason you can't use key value instead of temp store

fxa’s picture

Yes, this is only a part of the code... but the problem is in the tempstore line.
When I input a certain url in a webform, I must be capable to get the last verified time.
So I thought that tempstore.shared was the easiest way to handle this.
What do you mean with key value...

larowlan’s picture

The key.value service provides a similar API without needing sessions

fxa’s picture

Replacing
$store = \Drupal::service('tempstore.shared')->get('fjmodule.urls');
by
$store = \Drupal::service('keyvalue.expirable')->get('fjmodule.urls');
solves the problem... no more errors.
Thanks for the suggestion.

larowlan’s picture

Status: Postponed (maintainer needs more info) » Fixed

Nice! Thanks for reporting back

Status: Fixed » Closed (fixed)

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