0

I want to run my custom cron job, and I don’t know why it’s not registered or running.
In the database, I don’t see it registered—there’s no record of it.
In the log files, I don’t see any log messages from it, not even an error.
The code is correct—I’ve used it on an old website, and it was working. I even used it in a previous version of this website. This current version of the same website was hosted on shared hosting, and it was working. After moving to AWS, it’s not even registered or running.
What’s the issue?
I've tried everything I know: changed permissions, changed schedules in crontab.xml to every 5 minutes, cleared cache, upgraded the system—nothing worked. I've waited for it to execute the previous two days since I set it to run every 24 hours, but it’s not running.
I’ve also used all the AI chatbots I can, but still no solution.
I really appreciate any suggestions or notes. If you have any, please don’t hesitate to provide them. 🙏

Here is a full overview of everything :

ubuntu@ip-172-31-38-33:/var/www/html/magento$ ls -l /var/www/html/magento/app/code/MetaCares/Chatbot
total 24
drwxr-xr-x 3 www-data www-data 4096 Mar  3 11:04 Controller
drwxr-xr-x 2 www-data www-data 4096 Mar  3 11:04 Cron
drwxr-xr-x 2 www-data www-data 4096 Mar 11 13:15 Model
drwxr-xr-x 4 www-data www-data 4096 Mar 21 10:27 etc
-rw-r--r-- 1 www-data www-data  170 Mar  3 11:04 registration.php
drwxr-xr-x 3 www-data www-data 4096 Mar  3 11:04 view
ubuntu@ip-172-31-38-33:/var/www/html/magento$ grep 'MetaCares_Chatbot' /var/www/html/magento/app/etc/config.php
        'MetaCares_Chatbot' => 1,
ubuntu@ip-172-31-38-33:/var/www/html/magento$ sudo -u www-data /usr/bin/php8.3 /var/www/html/magento/bin/magento module:status MetaCares_Chatbot
MetaCares_Chatbot : Module is enabled
ubuntu@ip-172-31-38-33:/var/www/html/magento$ sudo cat /etc/crontab
# /etc/crontab: system-wide crontab
# Unlike any other crontab you don't have to run the `crontab'
# command to install the new version when you edit this file
# and files in /etc/cron.d. These files also have username fields,
# that none of the other crontabs do.

SHELL=/bin/sh
# You can also override PATH, but by default, newer versions inherit it from the environment
#PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin

# Example of job definition:
# .---------------- minute (0 - 59)
# |  .------------- hour (0 - 23)
# |  |  .---------- day of month (1 - 31)
# |  |  |  .------- month (1 - 12) OR jan,feb,mar,apr ...
# |  |  |  |  .---- day of week (0 - 6) (Sunday=0 or 7) OR sun,mon,tue,wed,thu,fri,sat
# |  |  |  |  |
# *  *  *  *  * user-name command to be executed
17 *    * * *   root    cd / && run-parts --report /etc/cron.hourly
25 6    * * *   root    test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.daily; }
47 6    * * 7   root    test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.weekly; }
52 6    1 * *   root    test -x /usr/sbin/anacron || { cd / && run-parts --report /etc/cron.monthly; }
#
ubuntu@ip-172-31-38-33:/var/www/html/magento$ crontab -l

#~ MAGENTO START f37deed947b2ea951ad6f939b8ab752bc79587e3d77f40d06f20f0657c98e94d
* * * * * www-data  /usr/bin/php8.3 /var/www/html/magento/bin/magento cron:run 2>&1 | grep -v "Ran jobs by schedule" >> /var/www/html/magento/var/log/magento.cron.log
* * * * * www-data /usr/bin/php8.3 /var/www/html/magento/update/cron.php
* * * * * www-data /usr/bin/php8.3 /var/www/html/magento/bin/magento setup:cron:run
#~ MAGENTO END f37deed947b2ea951ad6f939b8ab752bc79587e3d77f40d06f20f0657c98e94d

ubuntu@ip-172-31-38-33:/var/www/html/magento$ sudo -u www-data /usr/bin/php8.3 /var/www/html/magento/bin/magento cron:install
Crontab has already been generated and saved
ubuntu@ip-172-31-38-33:/var/www/html/magento$ sudo -u www-data /usr/bin/php8.3 /var/www/html/magento/bin/magento cache:clean
Cleaned cache types:
config
layout
block_html
collections
reflection
db_ddl
compiled_config
eav
customer_notification
config_integration
config_integration_api
full_page
config_webservice
translate
ubuntu@ip-172-31-38-33:/var/www/html/magento$ sudo -u www-data /usr/bin/php8.3 /var/www/html/magento/bin/magento cron:run
Ran jobs by schedule.
ubuntu@ip-172-31-38-33:/var/www/html/magento$ sudo -u www-data /usr/bin/php8.3 /var/www/html/magento/bin/magento cron:run
Ran jobs by schedule.
ubuntu@ip-172-31-38-33:/var/www/html/magento$ mysql -u my-username -p my-database
Enter password:
Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 812095
Server version: 8.0.41-0ubuntu0.24.04.1 (Ubuntu)

Copyright (c) 2000, 2025, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql> SELECT DISTINCT job_code FROM cron_schedule;
+-----------------------------------------------+
| job_code                                      |
+-----------------------------------------------+
| amasty_base_instance_registration             |
| amasty_cron_activity                          |
| bulk_cleanup                                  |
| bulk_mark_incomplete_operations_as_failed     |
| captcha_delete_expired_images                 |
| captcha_delete_old_attempts                   |
| catalog_index_refresh_price                   |
| catalog_product_attribute_value_synchronize   |
| catalog_product_frontend_actions_flush        |
| catalog_product_outdated_price_values_cleanup |
| consumers_runner                              |
| core_process_feed                             |
| expired_tokens_cleanup                        |
| indexer_clean_all_changelogs                  |
| indexer_reindex_all_invalid                   |
| indexer_update_all_views                      |
| magento_newrelicreporting_cron                |
| messagequeue_clean_outdated_locks             |
| newsletter_send_all                           |
| outdated_authentication_failures_cleanup      |
| sales_clean_orders                            |
| sales_grid_order_async_insert                 |
| sales_grid_order_creditmemo_async_insert      |
| sales_grid_order_invoice_async_insert         |
| sales_grid_order_shipment_async_insert        |
| sales_send_order_creditmemo_emails            |
| sales_send_order_emails                       |
| sales_send_order_invoice_emails               |
| sales_send_order_shipment_emails              |
| security_deactivate_expired_users             |
| stripe_capture_authorizations                 |
| stripe_webhooks_configure                     |
| stripe_webhooks_ping                          |
| stripe_webhook_cleanup_tables                 |
| stripe_webhook_events_retry                   |
+-----------------------------------------------+
35 rows in set (0.00 sec)

mysql> exit
Bye

system.log file content:

[2025-03-21T11:04:07.138051+00:00] main.ERROR: crontab -l 2>/dev/null 2>&1
no crontab for www-data [] []
[2025-03-21T11:04:07.140750+00:00] main.ERROR: crontab -l 2>/dev/null 2>&1
no crontab for www-data [] []
[2025-03-21T11:04:07.146243+00:00] main.INFO: echo "
#~ MAGENTO START f37deed947b2ea951ad6f939b8ab752bc79587e3d77f40d06f20f0657c98e94d
* * * * * /usr/bin/php8.3 /var/www/html/magento/bin/magento cron:run 2>&1 | grep -v \"Ran jobs by schedule\" >> /var/www/html/magento/var/log/magento.cron.log
#~ MAGENTO END f37deed947b2ea951ad6f939b8ab752bc79587e3d77f40d06f20f0657c98e94d
" 2>&1 | crontab - 2>&1
 [] []
[2025-03-21T11:14:42.345633+00:00] main.INFO: crontab -l 2>/dev/null 2>&1

#~ MAGENTO START f37deed947b2ea951ad6f939b8ab752bc79587e3d77f40d06f20f0657c98e94d
* * * * * /usr/bin/php8.3 /var/www/html/magento/bin/magento cron:run 2>&1 | grep -v "Ran jobs by schedule" >> /var/www/html/magento/var/log/magento.cron.log
#~ MAGENTO END f37deed947b2ea951ad6f939b8ab752bc79587e3d77f40d06f20f0657c98e94d
 [] []

cron.log file content:

[2025-03-21T11:14:02.740900+00:00] main.INFO: Cron Job indexer_reindex_all_invalid is run [] []
[2025-03-21T11:14:02.749678+00:00] main.INFO: Cron Job indexer_reindex_all_invalid is successfully finished. Statistics: {"sum":0.0089640617370605,"count":1,"realmem":0,"emalloc":456448,"realmem_start":189267968,"emalloc_start":177734544} [] []
[2025-03-21T11:14:02.775097+00:00] main.INFO: Cron Job indexer_update_all_views is run [] []
[2025-03-21T11:14:02.779181+00:00] main.INFO: Cron Job indexer_update_all_views is successfully finished. Statistics: {"sum":0.0040781497955322,"count":1,"realmem":0,"emalloc":115968,"realmem_start":189267968,"emalloc_start":178193200} [] []
[2025-03-21T11:14:02.919780+00:00] main.INFO: Cron Job consumers_runner is run [] []
[2025-03-21T11:14:02.927706+00:00] main.INFO: Cron Job consumers_runner is successfully finished. Statistics: {"sum":0.008112907409668,"count":1,"realmem":0,"emalloc":188096,"realmem_start":189267968,"emalloc_start":178074696} [] []
.... and alot of other messages but my cron job message not appearing in the message list

Location of crontab.xml in Magento Module

magento
└── app
    └── code
        └── MetaCares
            └── Chatbot
                └── etc
                    ├── acl.xml
                    ├── adminhtml
                    │   └── ... (folders inside adminhtml)
                    ├── crontab.xml
                    ├── frontend
                    │   └── ... (folders inside frontend)
                    └── module.xml

crontab.xml:

<?xml version="1.0"?>
<config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:noNamespaceSchemaLocation="urn:magento:module:Magento_Cron:etc/crontab.xsd">
    <group id="default">
        <job name="chatbot_update_products" instance="MetaCares\Chatbot\Cron\UpdateProducts"
            method="execute">
            <schedule>0 0 * * *</schedule>
        </job>
    </group>
</config>

Location of UpdateProducts.php in Magento Module

magento
└── app
    └── code
        └── MetaCares
            └── Chatbot
                └── etc
                |    ├── acl.xml
                |   ├── adminhtml
                |    │   └── ...
                |    ├── crontab.xml
                |    ├── frontend
                |    │   └── ...
                |    └── module.xml
                └── Cron
                |    ├── UpdateProducts.php

UpdateProducts.php:

<?php

namespace MetaCares\Chatbot\Cron;

use Psr\Log\LoggerInterface;
use Magento\Framework\App\ObjectManager;
use Magento\Catalog\Model\ResourceModel\Product\CollectionFactory;
use Magento\Catalog\Model\CategoryRepository;
use Magento\Framework\Encryption\EncryptorInterface;
use Magento\Framework\App\Config\ScopeConfigInterface;

class UpdateProducts
{
    protected $logger;
    private $productCollectionFactory;
    private $categoryRepository;
    private $weaviateEndpoint;
    private $weaviateApiKey;
    private $scopeConfig;
    private $encryptor;
    private $authorization;

    public function __construct(
        LoggerInterface $logger,
        CollectionFactory $productCollectionFactory,
        CategoryRepository $categoryRepository,
        ScopeConfigInterface $scopeConfig,
        EncryptorInterface $encryptor
    ) {
        $this->logger = $logger;
        $this->productCollectionFactory = $productCollectionFactory;
        $this->categoryRepository = $categoryRepository;
        $this->scopeConfig = $scopeConfig;
        $this->encryptor = $encryptor;
        $this->initializeApiKeys();
    }
    private function initializeApiKeys()
    {

        $this->weaviateEndpoint = $this->scopeConfig->getValue('chatbot/weaviate/endpoint', \Magento\Store\Model\ScopeInterface::SCOPE_STORE);
        $this->weaviateApiKey = $this->scopeConfig->getValue('chatbot/weaviate/api_key', \Magento\Store\Model\ScopeInterface::SCOPE_STORE);
        $this->authorization = $this->scopeConfig->getValue('chatbot/openai/authorization', \Magento\Store\Model\ScopeInterface::SCOPE_STORE);
        try {

            $this->weaviateApiKey = $this->encryptor->decrypt($this->weaviateApiKey);
            $this->authorization = $this->encryptor->decrypt($this->authorization);
        } catch (\Exception $e) {
            $this->logger->error("Error decrypting API keys: " . $e->getMessage());
            $this->weaviateApiKey = '';
        }
    }

    /**
     * Fetch products from Magento.
     */
    public function fetchProducts(): array
    {
        try {
            $productCollection = $this->productCollectionFactory->create();
            $productCollection->addAttributeToSelect([
                'name',
                'sku',
                'price',
                'description',
                'short_description',
                'category_ids'
            ]);

            $products = [];
            foreach ($productCollection as $product) {
                $products[] = [
                    'name' => $product->getName(),
                    'sku' => $product->getSku(),
                    'price' => $product->getPrice(),
                    'description' => $product->getDescription() ?? '',
                    'short_description' => $product->getShortDescription() ?? '',
                    'categories' => $this->getCategoryNames($product->getCategoryIds()),
                    'product_url' => $product->getUrlModel()->getUrl($product),
                ];
            }
            if (count($products) > 0) {
                $this->logger->info("Fetched " . count($products) . " products from Magento.");
            } else {
                $this->logger->info("NO Products are fetched from magento.");
            }
            return $products;
        } catch (\Exception $e) {
            $this->logger->error('Error fetching products: ' . $e->getMessage());
            $this->logger->error((string)$e);
            return [];
        }
    }

    /**
     * Push products to Weaviate, updating if they exist.
     */
    private function pushProductsToWeaviate(array $products): array
    {
        try {
            $results = [];
            foreach ($products as $product) {
                try {
                    $data = [
                        "class" => "Product",
                        "properties" => [
                            "name" => $product['name'],
                            "sku" => $product['sku'],
                            "price" => (float) $product['price'],
                            "description" => $product['description'],
                            "short_description" => $product['short_description'],
                            "categories" => $product['categories'],
                            "product_url" => $product['product_url']
                        ]
                    ];
                    $existingProduct = $this->getProductBySku($product['sku']);

                    if ($existingProduct) {
                        $results[] = $this->updateProductInWeaviate($existingProduct['_additional']['id'], $data);
                    } else {
                        $results[] = $this->insertProductToWeaviate($data);
                    }
                } catch (\Exception $e) {
                    $this->logger->error('Error processing product with SKU: ' . $product['sku'] . 'Error message : ' . $e->getMessage());
                    $this->logger->error((string)$e);
                }
            }
            return $results;
        } catch (\Exception $e) {
            $this->logger->error('Error push products to Weaviate : ' . $e->getMessage());
            $this->logger->error((string)$e);
            return [];
        }
    }

    /**
     * Get product by SKU from Weaviate.
     */
    private function getProductBySku(string $sku): ?array
    {
        $query = [
            "query" => "{
            Get {
                Product(where: {
                    path: [\"sku\"],
                    operator: Equal,
                    valueString: \"$sku\"
                }) {
                    _additional {
                        id
                    }
                    name
                    sku
                    price
                    description
                    short_description
                    categories
                    product_url
                }
            }
        }"
        ];

        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $this->weaviateEndpoint . '/v1/graphql');
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($query));
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Content-Type: application/json',
            'Authorization: Bearer ' . $this->weaviateApiKey,
            'X-Openai-Api-Key: ' . $this->authorization,
        ]);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $response = curl_exec($ch);
        $error = curl_error($ch);
        curl_close($ch);

        if ($error) {
            $this->logger->error("Error getting product by SKU ($sku): " . $error);
            return null;
        }

        $result = json_decode($response, true);
        return $result['data']['Get']['Product'][0] ?? null;
    }

    /**
     * Insert a new product into Weaviate.
     */
    private function insertProductToWeaviate(array $data): array
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $this->weaviateEndpoint . '/v1/objects');
        curl_setopt($ch, CURLOPT_POST, 1);
        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data));
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Content-Type: application/json',
            'Authorization: Bearer ' . $this->weaviateApiKey,
            'X-Openai-Api-Key: ' . $this->authorization,
        ]);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $response = curl_exec($ch);
        $error = curl_error($ch);
        curl_close($ch);

        if ($error) {
            $this->logger->error("Error inserting product into Weaviate: " . $error);
            return [];
        }
        return json_decode($response, true);
    }

    /**
     * Update an existing product in Weaviate.
     */
    private function updateProductInWeaviate(string $id, array $data): array
    {
        $deleteUrl = $this->weaviateEndpoint . "/v1/objects/Product/$id";
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $deleteUrl);
        curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "DELETE");
        curl_setopt($ch, CURLOPT_HTTPHEADER, [
            'Content-Type: application/json',
            'Authorization: Bearer ' . $this->weaviateApiKey,
            'X-Openai-Api-Key: ' . $this->authorization,
        ]);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $deleteResponse = curl_exec($ch);
        $deleteError = curl_error($ch);
        $deleteHttpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        curl_close($ch);

        if ($deleteError) {
            $this->logger->error("Error deleting product in Weaviate with ID ($id): " . $deleteError);
            return ['error' => $deleteError];
        }
        if ($deleteHttpCode !== 204) {
            $this->logger->error("Failed to delete product in Weaviate. HTTP Code: $deleteHttpCode, Response: $deleteResponse");
            return ['error' => "HTTP Code: $deleteHttpCode, Response: $deleteResponse"];
        }
        $insertData = [
            "class" => "Product",
            "properties" => $data['properties']
        ];
        $insertResponse = $this->insertProductToWeaviate($insertData);
        if (isset($insertResponse['error'])) {
            $this->logger->error("Error inserting product into Weaviate: " . json_encode($insertResponse['error']));
            return $insertResponse;
        }
        return $insertResponse;
    }

    /**
     * Get category names by IDs.
     */
    private function getCategoryNames(array $categoryIds): array
    {
        try {
            $categoryNames = [];

            foreach ($categoryIds as $categoryId) {
                try {
                    $category = $this->categoryRepository->get($categoryId);
                    $categoryNames[] = $category->getName();
                } catch (\Exception $e) {
                    $this->logger->error('Error getCategoryNames product with categoryId: ' . $categoryId . 'Error message : ' . $e->getMessage());
                    $this->logger->error((string)$e);
                    continue;
                }
            }
            return $categoryNames;
        } catch (\Exception $e) {
            $this->logger->error('Error  get category names: ' . $e->getMessage());
            $this->logger->error((string)$e);
            return [];
        }
    }


    public function execute()
    {
        $this->logger->info('Cron job for updating product data in Weaviate is starting');
        try {
            $products = $this->fetchProducts();
            if (!empty($products)) {
                $results = $this->pushProductsToWeaviate($products);
            }
            $this->logger->info('Cron job for updating product data in Weaviate is finished.');
        } catch (\Exception $e) {
            $this->logger->error('Cron job for updating product data in Weaviate failed: ' . $e->getMessage());
            $this->logger->error((string)$e);
        }
    }
}
1
  • Is this a problem with AWS, SSH, or Magento? Commented Mar 26 at 16:42

1 Answer 1

0

Based on this error: no crontab exists for www-data

[2025-03-21T11:04:07.138051+00:00] main.ERROR: crontab -l 2>/dev/null 2>&1
no crontab for www-data [] []
[2025-03-21T11:04:07.140750+00:00] main.ERROR: crontab -l 2>/dev/null 2>&1
no crontab for www-data [] []

Run sudo crontab -u www-data -e

this will open an empty file where you can manually add the Magento cron jobs.

Verify using sudo crontab -u www-data -l

Sign up to request clarification or add additional context in comments.

6 Comments

I run that command and I see this ubuntu@ip-172-31-38-33:/var/www/html/magento$ crontab -u www-data -e must be privileged to use -u
can u explain to me the issue, and thanks for answering 🙏
The error you're seeing (must be privileged to use -u) occurs because the crontab -u <user> -e command requires root privileges to edit the crontab of another user, in this case, the www-data user. Updated the command above.
look I run the second command u provided and after it the fris tcommand and this is what Isee now : sudo crontab -u www-data -l ----> #~ MAGENTO START * * * * * /usr/bin/php8.3 /var/www/html/magento/bin/magento cron:run 2>&1 | grep -v "Ran jobs by schedule" >> /var/www/html/magento/var/log/magento.cron.log #~ MAGENTO END \ sudo crontab -u www-data -e---->I #~ MAGENTO START * * * * * /usr/bin/php8.3 /var/www/html/magento/bin/magento cron:run 2>&1 | grep -v "Ran jobs by schedule" >> /var/www/html/magento/var/log/magento.cron.log #~ MAGENTO END
Did this work of still no execution of crontab?
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.