I have updated the search_api suite of modules to latest versions:

Drupal core version: 8.9.1
facets: 8.x-1.4
search_api: 8.x-1.17
search_api_attachments: 8.x-1.0-beta16
search_api_solr: 4.1.1
search_api_sorts: 8.x-1.0-beta1

When I visit the server detail page (config/search/search-api/server/solr - a Solr server type version 7.7.3) page, I see the following message:

There are currently 2 tasks pending for this server.
Pending tasks are created when operations on the server, such as deleting one or more items, cannot be executed because the server is currently unavailable (which will usually also create an entry in the Drupal logs). They are automatically tried again before any other operation is executed and the operation is aborted if the tasks could still not be executed, or if there are too many pending tasks to be executed in a single page request. In the latter case, you can use this form to manually execute all tasks and thus unblock the server again.

Pressing the "Execute tasks now" button I get the following WSOD:

The website encountered an unexpected error. Please try again later.

LogicException: The database connection is not serializable. This probably means you are serializing an object that has an indirect reference to the database connection. Adjust your code so that is not necessary. Alternatively, look at DependencySerializationTrait as a temporary solution. in Drupal\Core\Database\Connection->__sleep() (line 1573 of core/lib/Drupal/Core/Database/Connection.php).
serialize(Array) (Line: 157)
Drupal\Core\Batch\BatchStorage->doCreate(Array) (Line: 129)
Drupal\Core\Batch\BatchStorage->create(Array) (Line: 107)
Drupal\Core\ProxyClass\Batch\BatchStorage->create(Array) (Line: 926)
batch_process() (Line: 63)
Drupal\Core\Form\FormSubmitter->doSubmitForm(Array, Object) (Line: 593)
Drupal\Core\Form\FormBuilder->processForm('search_api_server_status', Array, Object) (Line: 321)
Drupal\Core\Form\FormBuilder->buildForm('Drupal\search_api\Form\ServerStatusForm', Object) (Line: 219)
Drupal\Core\Form\FormBuilder->getForm('Drupal\search_api\Form\ServerStatusForm', Object) (Line: 81)
Drupal\search_api\Controller\ServerController->page(Object)
call_user_func_array(Array, Array) (Line: 123)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 573)
Drupal\Core\Render\Renderer->executeInRenderContext(Object, Object) (Line: 124)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext(Array, Array) (Line: 97)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 151)
Symfony\Component\HttpKernel\HttpKernel->handleRaw(Object, 1) (Line: 68)
Symfony\Component\HttpKernel\HttpKernel->handle(Object, 1, 1) (Line: 57)
Drupal\Core\StackMiddleware\Session->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\KernelPreHandle->handle(Object, 1, 1) (Line: 106)
Drupal\page_cache\StackMiddleware\PageCache->pass(Object, 1, 1) (Line: 85)
Drupal\page_cache\StackMiddleware\PageCache->handle(Object, 1, 1) (Line: 47)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle(Object, 1, 1) (Line: 52)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle(Object, 1, 1) (Line: 23)
Stack\StackedHttpKernel->handle(Object, 1, 1) (Line: 708)
Drupal\Core\DrupalKernel->handle(Object) (Line: 19)

Comments

cristiroma created an issue. See original summary.

cristiroma’s picture

What I further did was to clear and rebuild the two indexes sitting on the server. In this moment the message with 'Pending operations' has disappeared, so the problem went away. However I think there still might be a problem on the batch.

Also forgot to mention the Solr core was fresh and empty, created using 'Get Config zip'. But the DB was cloned from production so it was out of sync with Solr.

drunken monkey’s picture

Status: Active » Postponed (maintainer needs more info)

Huh, weird. I already had a similar report recently (#3115179: Exception when saving search index field), but in neither case if have any idea how this would happen. From all I can see, the batch should only contain \Drupal\search_api\Task\TaskManager in its definition, and that already uses \Drupal\Core\DependencyInjection\DependencySerializationTrait. So, not sure how this would happen.
I think without further information on what data structure gets indexed, we won’t be able to get to the bottom of this.

drunken monkey’s picture

ethanstraffin’s picture

I'm seeing this also:

LogicException: The database connection is not serializable. This probably means you are serializing an object that has an indirect reference to the database connection. Adjust your code so that is not necessary. Alternatively, look at DependencySerializationTrait as a temporary solution. in Drupal\Core\Database\Connection->__sleep() (line 1574 of core/lib/Drupal/Core/Database/Connection.php).

This occurs while attempting to configure a Solr backend. We had previously employed the Search API Database Search module. That module is now disabled, and the original server and indexes deleted. My guess is that there is still some sort of cruft interfering with the intended operation. I'm fairly stumped at the moment but will do my best to troubleshoot.

ethanstraffin’s picture

Found the problem via the debugger. OpenSolr is providing the path field as "solr/CoreName" with no leading slash, but the module expects one (hence the default value). This isn't exactly the error message I'd have expected, but that single change cleared it.

avpaderno’s picture

Version: 8.x-1.17 » 8.x-1.x-dev
drunken monkey’s picture

Thanks for investigating, ethanstraffin! Then this sounds like more of a problem with the Solr backend? Please create an issue there and maybe link this one – I have no idea how one would lead to the other, but if it does, then that’s at least one mystery solved.

cristiroma’s picture

Issue summary: View changes
StatusFileSize
new32.01 KB
new66.23 KB
new125.27 KB
new20.72 KB

It happened again today and I've inspected with the debugger. What I did to get this this error was to copy a solr 7 core from a project to another project, restart solr. Basically I've 'reused it'.

When I did this, the Search API shown pending 2 tasks:

pending tasks

When I press the "Execute tasks now" the form submission handler tries to create a new task. What I think is happening is that the batch objects contains a reference to the 'form_state' object which has references to the search api backends where there are MySQL connections referenced.

web/core/includes/form.inc:926 - \Drupal::service('batch.storage')->create($batch);

web/core/lib/Drupal/Core/Batch/BatchStorage.php:151

  protected function doCreate(array $batch) {
    $this->connection->insert('batch')
      ->fields([
        'bid' => $batch['id'],
        'timestamp' => REQUEST_TIME,
        'token' => $this->csrfToken->get($batch['id']),
        'batch' => serialize($batch),
      ])
      ->execute();

serialize($batch) - That's where the error occurrs.


drunken monkey’s picture

Project: Search API » Search API Solr
Version: 8.x-1.x-dev » 4.x-dev
Component: General code » Code
Status: Postponed (maintainer needs more info) » Active

Awesome, thanks a lot for debugging this so thoroughly!
Seems this is a bug in the Solr backend plugin, then. The DB backend already implements __sleep() to prevent this problem – Solr should just follow suit.
Moving this issue accordingly.

(Having the server entity not serialize the backend plugin would otherwise also be an option, I guess? But I think I prefer having the backend plugins be serializable. Discussion welcome, though.)

mkalkbrenner’s picture

Project: Search API Solr » Search API
Version: 4.x-dev » 8.x-1.x-dev
Component: Code » General code
Priority: Normal » Major

These are the corresponding methods in the database backend:

  /**
   * Implements the magic __sleep() method.
   *
   * Prevents the database connection and logger from being serialized.
   */
  public function __sleep() {
    $properties = array_flip(parent::__sleep());
    unset($properties['database']);
    unset($properties['logger']);
    return array_keys($properties);
  }

  /**
   * Implements the magic __wakeup() method.
   *
   * Reloads the database connection and logger.
   */
  public function __wakeup() {
    parent::__wakeup();

    if (isset($this->configuration['database'])) {
      list($key, $target) = explode(':', $this->configuration['database'], 2);
      $this->database = CoreDatabase::getConnection($target, $key);
    }
  }

Obviously the Solr backend doesn't maintain a database connection ;-)
So let's have a look at the methods implemented in the BackendPluginBase:

  /**
   * Implements the magic __sleep() method.
   *
   * Prevents the server entity from being serialized.
   */
  public function __sleep() {
    if ($this->server) {
      $this->serverId = $this->server->id();
    }
    $properties = array_flip(parent::__sleep());
    unset($properties['server']);
    return array_keys($properties);
  }

  /**
   * Implements the magic __wakeup() method.
   *
   * Reloads the server entity.
   */
  public function __wakeup() {
    parent::__wakeup();

    if ($this->serverId) {
      $this->server = Server::load($this->serverId);
      $this->serverId = NULL;
    }
  }

I assume the error is caused by the logger. The logger is created by the BackendPluginBase. But it's serialization is handled by the Database Backend. This is wrong. Instead of doing the same in other backends, BackendPluginBase should take care about it.

abstract class BackendPluginBase extends ConfigurablePluginBase implements BackendInterface {

  use LoggerTrait;
mkalkbrenner’s picture

Status: Active » Needs review
StatusFileSize
new1.05 KB

drunken monkey’s picture

Project: Search API » Search API Solr
Component: General code » Code
Status: Needs review » Active

You’re right, thanks a lot for spotting this! Committed your patch.
However, as you can see in #9, the logger isn’t actually the (only) issue – it’s the $moduleHandler property on the Solr backend plugin. So, that will have to be handled, too – as said, either via DependencySerializationTrait (you’d just have to take care to call both the trait’s method and the parent method) or manually (which would have the downside of needing you to keep it up-to-date every time you add a new service as a property).

Or maybe we should just use DependencySerializationTrait in the backend plugin base class, if we generally expect backend plugins to be serializable? Not sure if that would count as a BC break, though – behavior would change a bit for child classes, which might lead to problems. (Though the ES backend, for one, should be fine – they just return array(); in their sleep() method.)

mkalkbrenner’s picture

I'll take a look ...

mkalkbrenner’s picture

Status: Active » Needs review
StatusFileSize
new1.05 KB

I'll add DependencySerializationTrait to the Solr Backend.

mkalkbrenner’s picture

StatusFileSize
new899 bytes

  • mkalkbrenner committed a7cae1d on 4.x
    Issue #3153153 by mkalkbrenner, cristiroma, drunken monkey:...
mkalkbrenner’s picture

Status: Needs review » Fixed

So I assume that this is fixed now.
Please re-open if not.

Status: Fixed » Closed (fixed)

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