1

I already experienced this same problem with Craft Commerce a while ago (Error on functions in queue: "Session does not exist in a console request.") and got a solution that solved the problem for the function described in that question, but this time the problem occurs on a different function and I can't seem to find a solution.

There's a connection with the Lightspeed API to update product stock values every 15 minutes and to import new products. These are all handled by the queue and work most of the time, but sometimes it throws an error saying "Session does not exist in a console request" Queue manager screenshot

Here are all functions that are performed in this action (I know it's a lot, but I am getting quite desperate):

Controller action

public function actionImportNewProducts()
{
    Stock::$plugin->lightspeedService->refreshToken();
    
    $allowedCategories = Craft::$app->request->getBodyParam('categories');

    $startParam = Craft::$app->request->getBodyParam('startDate');
    $startDate = new \DateTime($startParam['date']);

    $endParam = Craft::$app->request->getBodyParam('endDate');
    if (!$endParam) {
        $endDate = new \DateTime();
    } else {
        $endDate = new \DateTime($endParam['date']);
    }
    $endDate = $endDate->modify('tomorrow midnight');

    $limit = 100;
    $pages = Stock::$plugin->lightspeedService->getPagination();
    $productCount = 0;

    for ($page = 0; $page < $pages; $page++) {
        $offset = $page * $limit;
        $inventory = json_decode(Stock::$plugin->lightspeedService->getInventory($offset, '["ItemShops", "Category", "TaxClass"]'), true);

        $items = $inventory['Item'];
        foreach ($items as $item) {
            $createdAt = new \DateTime($item['createTime']);
            $createdAt = $createdAt->modify('midnight');

            if ($createdAt >= $startDate && $createdAt <= $endDate) {
                $category = $item['Category'];
                if (in_array($category['categoryID'], $allowedCategories)) {
                    if (!$item['archived'] or $item['archived'] == 'false') {
                        Stock::$plugin->productService->queueImportProduct($item);
                        $productCount++;
                    }
                }
            }
        }
    }

    Craft::$app->session->setNotice($productCount . ' producten aan het importeren.');
}

LightspeedService refreshToken

public function refreshToken()
{
    $refreshToken = Stock::getInstance()->settings->refreshToken;
    if (!$refreshToken) {
        Craft::$app->session->setError('Lightspeed refreshtoken ontbreekt');
        return false;
    }

    $client = new GuzzleClient();
    $url = 'https://cloud.lightspeedapp.com/oauth/access_token.php';
    $body['multipart'] = [
        [
            'name'     => 'client_id',
            'contents' => getenv('LIGHTSPEED_CLIENT_ID')
        ],
        [
            'name'     => 'client_secret',
            'contents' => getenv('LIGHTSPEED_CLIENT_SECRET')
        ],
        [
            'name'     => 'refresh_token',
            'contents' => $refreshToken
        ],
        [
            'name'     => 'grant_type',
            'contents' => 'refresh_token'
        ]
    ];

    try {
        $request = $client->request('POST', $url, $body);
        $response = $request->getBody()->getContents();
        $response = json_decode($response);

        $accessToken = $response->access_token;

        if (!$accessToken) {
            return $this->asJson($response);
        }

        $settings['accessToken'] = $accessToken;
        $plugin = Craft::$app->getPlugins()->getPlugin('stock');
        Craft::$app->getPlugins()->savePluginSettings($plugin, $settings);

        return $response;
    } catch (ClientException $e) {
        return $e->getMessage();
    }
}

LightspeedService getPagination

public function getPagination()
{
    $inventory = json_decode(Stock::$plugin->lightspeedService->getInventory(), true);
    $attributes = $inventory['@attributes'];

    $count = intval($attributes['count']);
    $limit = intval($attributes['limit']);

    return ceil($count / $limit);
}

LightspeedService getInventory

public function getInventory($offset = 0, $relations = null)
{
    Stock::$plugin->lightspeedService->refreshToken();
    
    $client = new GuzzleClient();
    $url = getenv('LIGHTSPEED_API_URL') . '/API/Account/' . getenv('LIGHTSPEED_ACCOUNT_ID') . '/Item.json?offset=' . $offset;
    if ($relations) {
        $url = $url . "&load_relations={$relations}";
    }

    $headers = [
        'Authorization' => 'Bearer ' . Stock::getInstance()->settings->accessToken
    ];

    try {
        $request = $client->request('GET', $url, [
            'headers' => $headers
        ]);
        $response = $request->getBody()->getContents();
        return $response;
    } catch (ClientException $e) {
        return $e->getMessage();
    }
}

ProductService queueImportProduct

public function queueImportProduct($item)
{
    Craft::$app->queue->push(new ImportProduct([
        'item' => $item
    ]));
}

Job importProduct

public function execute($queue)
{
    Stock::$plugin->productService->importProduct($this->item);
}

ProductService importProduct

I had read in another question that it could help to replace all product updates by DB queries, but that didn't solve my problem.

public function importProduct($item)
{
    $sku = $item['systemSku'];
    $price = Stock::$plugin->lightspeedService->getDefaultPrice($item);
    $stock = Stock::$plugin->lightspeedService->getItemQoh($item);
    $productTypeId = Stock::$plugin->productService->getProductType($item['Category']);
    $taxCategoryId = Stock::$plugin->lightspeedService->getTaxCategoryId($item['TaxClass']['taxClassID']);
    $variant = Variant::find()->sku($sku)->one();

    if (!$variant) {
        $product = new Product();
        $product->typeId = $productTypeId;
        $product->enabled = false;
        $product->title = $item['description'];
        $product->promotable = true;
        $product->taxCategoryId = $taxCategoryId;
        
        $variant = new Variant();
        $variant->isDefault = true;

        $variant->sku = $sku;
        $variant->price = (float) $price;
        $variant->stock = $stock;

        $product->setVariants([$variant]);
        Craft::$app->elements->saveElement($product);
    } else {
        $product = $variant->product;

        Craft::$app->getDb()->createCommand()->update('{{%commerce_products}}',
            [
                'taxCategoryId' => $taxCategoryId,
            ],
            [
                'id' => $variant->product->id
            ]
        )->execute();

        Craft::$app->getDb()->createCommand()->update('{{%commerce_variants}}',
            [
                'sku' => $sku,
                'price' => (float) $price,
                'stock' => $stock
            ],
            [
                'id' => $variant->id
            ]
        )->execute();
    }

    $lightspeedProductRecord = LightspeedProductsRecord::findOne(['itemId' => $item['itemID']]);
    if (!$lightspeedProductRecord) {
        $lightspeedProductRecord = new LightspeedProductsRecord();
        $lightspeedProductRecord->itemId = $item['itemID'];
    }

    $lightspeedProductRecord->variantId = $variant->id;
    $lightspeedProductRecord->save();
}

Any help will be appreciated!

2

Ok so with these the trick is to look for anything that might involve a request session, which is not available when you're running things via a console request.

In this case there's at least one obvious suspect line:

Craft::$app->session->setError('Lightspeed....);

Indeed there's more than one of these.

It's basically the same problem as previously - i.e. if there's no session, then you can't set errors on the session (or retrieve a cart from the session).

So you might need to check if the current request is a console request (if this code is ever run in a non console way) ... And deal with errors differently if so.

if (Craft::$app->getRequest()->getIsConsoleRequest()) {
   ...send errors to a log file, email an alert, ....
}

(As to why this is running as a console request - it depends how it is called. E.g. you're explicitly running it from the console, or your queue runner is doing so....)

| improve this answer | |

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.