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
Comment #2
cilefen commentedIt 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.
Comment #3
larowlanAre you running redirect after login module?
#3214949: Headers have already been sent after upgrade to Drupal 9.2 (can't login)
Comment #4
fxa commentedSome 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)
Comment #5
larowlanCan you describe the intention of the code so we could perhaps suggest an alternative approach
Temp store relies on a session I think
Comment #6
fxa commentedI 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.
Comment #7
larowlanI 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
Comment #8
fxa commentedYes, 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...
Comment #9
larowlanThe key.value service provides a similar API without needing sessions
Comment #10
fxa commentedReplacing
$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.
Comment #11
larowlanNice! Thanks for reporting back