prompt: We are currently solving the following issue within our repository. Here is the issue text:
  --- BEGIN ISSUE ---
  Update prices separately
  We update price files only after successful catalog data update. Sometimes we have struggle with data update, but we still need to update price files, otherwise we will get penalties from aggregators.
  
  We should make the price files update independent of the catalog data update.
  We can try these approaches:
  1) Update files in separate celery cron task
  2) Update files in finally block of update_catalog task 
  
  --- END ISSUE ---
  
  Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
  --- BEGIN FILES ---
  Path: `shopelectro/tasks.py`
  Content:
  ```
  1 from contextlib import contextmanager
  2 
  3 from django.conf import settings
  4 from django.core.management import call_command
  5 from selenium.common.exceptions import WebDriverException
  6 
  7 from shopelectro import selenium
  8 from shopelectro.celery import app
  9 from shopelectro.report import TelegramReport
  10 from shopelectro.models import CategoryPage
  11 from shopelectro.management.commands._update_catalog import utils
  12 
  13 
  14 @contextmanager
  15 def report():
  16     try:
  17         yield
  18     except Exception as error:
  19         utils.report(str(error))
  20         raise error
  21 
  22 
  23 @app.task
  24 def generate_price_files():
  25     with report():
  26         call_command('price')
  27         print('Generate prices complete.')
  28 
  29 
  30 @app.task
  31 def generate_excel_file():
  32     with report():
  33         call_command('excel')
  34         print('Generate excel complete.')
  35 
  36 
  37 @app.task
  38 def collect_static():
  39     with report():
  40         call_command('collectstatic', '--noinput')
  41 
  42 
  43 @app.task
  44 def update_catalog_command():
  45     with report():
  46         call_command('update_catalog')
  47 
  48 
  49 @app.task
  50 def update_default_templates():
  51     with report():
  52         call_command('update_default_templates')
  53 
  54 
  55 @app.task(autoretry_for=(Exception,), max_retries=3, default_retry_delay=60*10)  # Ignore PycodestyleBear (E226)
  56 def update_catalog():
  57     # http://docs.celeryproject.org/en/latest/userguide/canvas.html#map-starmap
  58     return [
  59         update_catalog_command(),
  60         update_default_templates(),
  61         generate_price_files(),
  62         generate_excel_file(),
  63         collect_static()
  64     ]
  65 
  66 
  67 @app.task(
  68     bind=True,
  69     autoretry_for=(WebDriverException, AssertionError),
  70     retry_kwargs={'max_retries': settings.CHECK_PURCHASE_RETRIES},
  71 )
  72 def check_purchase(self):
  73     try:
  74         with selenium.SiteDriver(site_url=settings.BASE_URL) as driver:
  75             category_page = selenium.CategoryPage(driver, CategoryPage.objects.first().slug)
  76             category_page.load()
  77             category_page.add_to_cart()
  78 
  79             order_page = selenium.OrderPage(driver)
  80             order_page.load()
  81             order_page.fill_contacts()
  82             order_page.make_order()
  83 
  84             success_page = selenium.SuccessPage(driver)
  85             assert success_page.is_success()
  86     except (WebDriverException, AssertionError) as err:
  87         if self.request.retries + 1 > self.max_retries:
  88             # report on the last attempt
  89             TelegramReport().send(f'Can\'t buy a product. Got the error: {err}')
  90         raise err
  91
  ```
  
  Path: `shopelectro/celery.py`
  Content:
  ```
  1 from __future__ import absolute_import, unicode_literals
  2 from datetime import timedelta
  3 import os
  4 
  5 from celery import Celery
  6 from kombu import Exchange, Queue
  7 
  8 # set the default Django settings module for the 'celery' program.
  9 os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'shopelectro.settings.local')
  10 
  11 app = Celery('shopelectro')
  12 
  13 # Exchanges
  14 default_exchange = Exchange('default', type='direct')
  15 utils_exchange = Exchange('utils', type='direct')
  16 
  17 # http://docs.celeryproject.org/en/latest/userguide/tasks.html
  18 task_queues = (
  19     Queue(
  20         name='default',
  21         exchange=default_exchange,
  22         routing_key='default',
  23     ),
  24     Queue(
  25         name='mail',
  26         exchange=utils_exchange,
  27         routing_key='utils.mail',
  28     ),
  29     Queue(
  30         name='command',
  31         exchange=utils_exchange,
  32         routing_key='utils.command',
  33     )
  34 )
  35 
  36 # http://docs.celeryproject.org/en/latest/userguide/periodic-tasks.html
  37 beat_schedule = {
  38     'update-catalog': {
  39         'task': 'shopelectro.tasks.update_catalog',
  40         'schedule': timedelta(hours=2).total_seconds(),
  41     },
  42     'check-purchase': {
  43         'task': 'shopelectro.tasks.check_purchase',
  44         'schedule': timedelta(days=1).total_seconds(),
  45     },
  46 }
  47 
  48 # http://docs.celeryproject.org/en/master/userguide/routing.html
  49 task_routes = {
  50     'shopelectro.tasks.update_catalog': {
  51         'queue': 'command',
  52         'routing_key': 'utils.command',
  53         'priority': 30,
  54     },
  55     'shopelectro.tasks.check_purchase': {
  56         'queue': 'command',
  57         'routing_key': 'utils.command',
  58         'priority': 20,
  59     },
  60     'ecommerce.tasks.send_mail': {
  61         'queue': 'mail',
  62         'routing_key': 'utils.mail',
  63         'priority': 50,
  64     },
  65 }
  66 
  67 # Using a string here means the worker don't have to serialize
  68 # the configuration object to child processes.
  69 # - namespace='CELERY' means all celery-related configuration keys
  70 #   should have a `CELERY_` prefix.
  71 app.config_from_object('django.conf:settings', namespace='CELERY')
  72 
  73 # http://docs.celeryproject.org/en/latest/userguide/configuration.html
  74 
  75 BROCKER_URL = (
  76     f'amqp://{os.environ["RABBITMQ_DEFAULT_USER"]}:{os.environ["RABBITMQ_DEFAULT_PASS"]}'
  77     f'@{os.environ["RABBITMQ_URL"]}:{os.environ["RABBITMQ_PORT"]}/'
  78 )
  79 app.conf.update(
  80     broker_url=BROCKER_URL,
  81     broker_heartbeat=30,
  82     task_acks_late=True,
  83     task_default_queue='default',
  84     task_default_exchange='default',
  85     task_default_routing_key='default',
  86     worker_pool_restarts=True,
  87     task_routes=task_routes,
  88     task_queues=task_queues,
  89     beat_schedule=beat_schedule,
  90     worker_max_memory_per_child=200000,  # after 250MB will restart
  91 )
  92 
  93 # Load task modules from all registered Django app configs.
  94 app.autodiscover_tasks()
  95
  ```
  --- END FILES ---
  
  Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.
  
  Here is an example:
  
  ```diff
  diff --git a/examples/server_async.py b/examples/server_async.py
  --- a/examples/server_async.py
  +++ b/examples/server_async.py
  @@ -313,4 +313,4 @@
   
   
   if __name__ == "__main__":
  -    asyncio.run(run_async_server("."), debug=True)
  +    asyncio.run(run_async_server(), debug=True)
  diff --git a/examples/server_sync.py b/examples/server_sync.py
  --- a/examples/server_sync.py
  +++ b/examples/server_sync.py
  @@ -313,5 +313,5 @@
   
   
   if __name__ == "__main__":
  -    server = run_sync_server(".")
  +    server = run_sync_server()
       server.shutdown()
  
  ```
  
golden_diff: diff --git a/shopelectro/celery.py b/shopelectro/celery.py
  --- a/shopelectro/celery.py
  +++ b/shopelectro/celery.py
  @@ -39,6 +39,10 @@
           'task': 'shopelectro.tasks.update_catalog',
           'schedule': timedelta(hours=2).total_seconds(),
       },
  +    'update-prices': {
  +        'task': 'shopelectro.tasks.update_prices',
  +        'schedule': timedelta(hours=1).total_seconds(),
  +    },
       'check-purchase': {
           'task': 'shopelectro.tasks.check_purchase',
           'schedule': timedelta(days=1).total_seconds(),
  @@ -52,6 +56,11 @@
           'routing_key': 'utils.command',
           'priority': 30,
       },
  +    'shopelectro.tasks.update_prices': {
  +        'queue': 'command',
  +        'routing_key': 'utils.command',
  +        'priority': 50,
  +    },
       'shopelectro.tasks.check_purchase': {
           'queue': 'command',
           'routing_key': 'utils.command',
  diff --git a/shopelectro/tasks.py b/shopelectro/tasks.py
  --- a/shopelectro/tasks.py
  +++ b/shopelectro/tasks.py
  @@ -58,9 +58,16 @@
       return [
           update_catalog_command(),
           update_default_templates(),
  +        collect_static(),
  +    ]
  +
  +
  +@app.task(autoretry_for=(Exception,), max_retries=3, default_retry_delay=60*10)  # Ignore PycodestyleBear (E226)
  +def update_prices():
  +    return [
           generate_price_files(),
           generate_excel_file(),
  -        collect_static()
  +        collect_static(),
       ]
  
verification_info: {"golden_diff": "diff --git a/shopelectro/celery.py b/shopelectro/celery.py\n--- a/shopelectro/celery.py\n+++ b/shopelectro/celery.py\n@@ -39,6 +39,10 @@\n         'task': 'shopelectro.tasks.update_catalog',\n         'schedule': timedelta(hours=2).total_seconds(),\n     },\n+    'update-prices': {\n+        'task': 'shopelectro.tasks.update_prices',\n+        'schedule': timedelta(hours=1).total_seconds(),\n+    },\n     'check-purchase': {\n         'task': 'shopelectro.tasks.check_purchase',\n         'schedule': timedelta(days=1).total_seconds(),\n@@ -52,6 +56,11 @@\n         'routing_key': 'utils.command',\n         'priority': 30,\n     },\n+    'shopelectro.tasks.update_prices': {\n+        'queue': 'command',\n+        'routing_key': 'utils.command',\n+        'priority': 50,\n+    },\n     'shopelectro.tasks.check_purchase': {\n         'queue': 'command',\n         'routing_key': 'utils.command',\ndiff --git a/shopelectro/tasks.py b/shopelectro/tasks.py\n--- a/shopelectro/tasks.py\n+++ b/shopelectro/tasks.py\n@@ -58,9 +58,16 @@\n     return [\n         update_catalog_command(),\n         update_default_templates(),\n+        collect_static(),\n+    ]\n+\n+\n+@app.task(autoretry_for=(Exception,), max_retries=3, default_retry_delay=60*10)  # Ignore PycodestyleBear (E226)\n+def update_prices():\n+    return [\n         generate_price_files(),\n         generate_excel_file(),\n-        collect_static()\n+        collect_static(),\n     ]\n", "issue": "Update prices separately\nWe update price files only after successful catalog data update. Sometimes we have struggle with data update, but we still need to update price files, otherwise we will get penalties from aggregators.\r\n\r\nWe should make the price files update independent of the catalog data update.\r\nWe can try these approaches:\r\n1) Update files in separate celery cron task\r\n2) Update files in finally block of update_catalog task \n", "before_files": [{"content": "from contextlib import contextmanager\n\nfrom django.conf import settings\nfrom django.core.management import call_command\nfrom selenium.common.exceptions import WebDriverException\n\nfrom shopelectro import selenium\nfrom shopelectro.celery import app\nfrom shopelectro.report import TelegramReport\nfrom shopelectro.models import CategoryPage\nfrom shopelectro.management.commands._update_catalog import utils\n\n\n@contextmanager\ndef report():\n    try:\n        yield\n    except Exception as error:\n        utils.report(str(error))\n        raise error\n\n\n@app.task\ndef generate_price_files():\n    with report():\n        call_command('price')\n        print('Generate prices complete.')\n\n\n@app.task\ndef generate_excel_file():\n    with report():\n        call_command('excel')\n        print('Generate excel complete.')\n\n\n@app.task\ndef collect_static():\n    with report():\n        call_command('collectstatic', '--noinput')\n\n\n@app.task\ndef update_catalog_command():\n    with report():\n        call_command('update_catalog')\n\n\n@app.task\ndef update_default_templates():\n    with report():\n        call_command('update_default_templates')\n\n\n@app.task(autoretry_for=(Exception,), max_retries=3, default_retry_delay=60*10)  # Ignore PycodestyleBear (E226)\ndef update_catalog():\n    # http://docs.celeryproject.org/en/latest/userguide/canvas.html#map-starmap\n    return [\n        update_catalog_command(),\n        update_default_templates(),\n        generate_price_files(),\n        generate_excel_file(),\n        collect_static()\n    ]\n\n\n@app.task(\n    bind=True,\n    autoretry_for=(WebDriverException, AssertionError),\n    retry_kwargs={'max_retries': settings.CHECK_PURCHASE_RETRIES},\n)\ndef check_purchase(self):\n    try:\n        with selenium.SiteDriver(site_url=settings.BASE_URL) as driver:\n            category_page = selenium.CategoryPage(driver, CategoryPage.objects.first().slug)\n            category_page.load()\n            category_page.add_to_cart()\n\n            order_page = selenium.OrderPage(driver)\n            order_page.load()\n            order_page.fill_contacts()\n            order_page.make_order()\n\n            success_page = selenium.SuccessPage(driver)\n            assert success_page.is_success()\n    except (WebDriverException, AssertionError) as err:\n        if self.request.retries + 1 > self.max_retries:\n            # report on the last attempt\n            TelegramReport().send(f'Can\\'t buy a product. Got the error: {err}')\n        raise err\n", "path": "shopelectro/tasks.py"}, {"content": "from __future__ import absolute_import, unicode_literals\nfrom datetime import timedelta\nimport os\n\nfrom celery import Celery\nfrom kombu import Exchange, Queue\n\n# set the default Django settings module for the 'celery' program.\nos.environ.setdefault('DJANGO_SETTINGS_MODULE', 'shopelectro.settings.local')\n\napp = Celery('shopelectro')\n\n# Exchanges\ndefault_exchange = Exchange('default', type='direct')\nutils_exchange = Exchange('utils', type='direct')\n\n# http://docs.celeryproject.org/en/latest/userguide/tasks.html\ntask_queues = (\n    Queue(\n        name='default',\n        exchange=default_exchange,\n        routing_key='default',\n    ),\n    Queue(\n        name='mail',\n        exchange=utils_exchange,\n        routing_key='utils.mail',\n    ),\n    Queue(\n        name='command',\n        exchange=utils_exchange,\n        routing_key='utils.command',\n    )\n)\n\n# http://docs.celeryproject.org/en/latest/userguide/periodic-tasks.html\nbeat_schedule = {\n    'update-catalog': {\n        'task': 'shopelectro.tasks.update_catalog',\n        'schedule': timedelta(hours=2).total_seconds(),\n    },\n    'check-purchase': {\n        'task': 'shopelectro.tasks.check_purchase',\n        'schedule': timedelta(days=1).total_seconds(),\n    },\n}\n\n# http://docs.celeryproject.org/en/master/userguide/routing.html\ntask_routes = {\n    'shopelectro.tasks.update_catalog': {\n        'queue': 'command',\n        'routing_key': 'utils.command',\n        'priority': 30,\n    },\n    'shopelectro.tasks.check_purchase': {\n        'queue': 'command',\n        'routing_key': 'utils.command',\n        'priority': 20,\n    },\n    'ecommerce.tasks.send_mail': {\n        'queue': 'mail',\n        'routing_key': 'utils.mail',\n        'priority': 50,\n    },\n}\n\n# Using a string here means the worker don't have to serialize\n# the configuration object to child processes.\n# - namespace='CELERY' means all celery-related configuration keys\n#   should have a `CELERY_` prefix.\napp.config_from_object('django.conf:settings', namespace='CELERY')\n\n# http://docs.celeryproject.org/en/latest/userguide/configuration.html\n\nBROCKER_URL = (\n    f'amqp://{os.environ[\"RABBITMQ_DEFAULT_USER\"]}:{os.environ[\"RABBITMQ_DEFAULT_PASS\"]}'\n    f'@{os.environ[\"RABBITMQ_URL\"]}:{os.environ[\"RABBITMQ_PORT\"]}/'\n)\napp.conf.update(\n    broker_url=BROCKER_URL,\n    broker_heartbeat=30,\n    task_acks_late=True,\n    task_default_queue='default',\n    task_default_exchange='default',\n    task_default_routing_key='default',\n    worker_pool_restarts=True,\n    task_routes=task_routes,\n    task_queues=task_queues,\n    beat_schedule=beat_schedule,\n    worker_max_memory_per_child=200000,  # after 250MB will restart\n)\n\n# Load task modules from all registered Django app configs.\napp.autodiscover_tasks()\n", "path": "shopelectro/celery.py"}], "after_files": [{"content": "from contextlib import contextmanager\n\nfrom django.conf import settings\nfrom django.core.management import call_command\nfrom selenium.common.exceptions import WebDriverException\n\nfrom shopelectro import selenium\nfrom shopelectro.celery import app\nfrom shopelectro.report import TelegramReport\nfrom shopelectro.models import CategoryPage\nfrom shopelectro.management.commands._update_catalog import utils\n\n\n@contextmanager\ndef report():\n    try:\n        yield\n    except Exception as error:\n        utils.report(str(error))\n        raise error\n\n\n@app.task\ndef generate_price_files():\n    with report():\n        call_command('price')\n        print('Generate prices complete.')\n\n\n@app.task\ndef generate_excel_file():\n    with report():\n        call_command('excel')\n        print('Generate excel complete.')\n\n\n@app.task\ndef collect_static():\n    with report():\n        call_command('collectstatic', '--noinput')\n\n\n@app.task\ndef update_catalog_command():\n    with report():\n        call_command('update_catalog')\n\n\n@app.task\ndef update_default_templates():\n    with report():\n        call_command('update_default_templates')\n\n\n@app.task(autoretry_for=(Exception,), max_retries=3, default_retry_delay=60*10)  # Ignore PycodestyleBear (E226)\ndef update_catalog():\n    # http://docs.celeryproject.org/en/latest/userguide/canvas.html#map-starmap\n    return [\n        update_catalog_command(),\n        update_default_templates(),\n        collect_static(),\n    ]\n\n\n@app.task(autoretry_for=(Exception,), max_retries=3, default_retry_delay=60*10)  # Ignore PycodestyleBear (E226)\ndef update_prices():\n    return [\n        generate_price_files(),\n        generate_excel_file(),\n        collect_static(),\n    ]\n\n\n@app.task(\n    bind=True,\n    autoretry_for=(WebDriverException, AssertionError),\n    retry_kwargs={'max_retries': settings.CHECK_PURCHASE_RETRIES},\n)\ndef check_purchase(self):\n    try:\n        with selenium.SiteDriver(site_url=settings.BASE_URL) as driver:\n            category_page = selenium.CategoryPage(driver, CategoryPage.objects.first().slug)\n            category_page.load()\n            category_page.add_to_cart()\n\n            order_page = selenium.OrderPage(driver)\n            order_page.load()\n            order_page.fill_contacts()\n            order_page.make_order()\n\n            success_page = selenium.SuccessPage(driver)\n            assert success_page.is_success()\n    except (WebDriverException, AssertionError) as err:\n        if self.request.retries + 1 > self.max_retries:\n            # report on the last attempt\n            TelegramReport().send(f'Can\\'t buy a product. Got the error: {err}')\n        raise err\n", "path": "shopelectro/tasks.py"}, {"content": "from __future__ import absolute_import, unicode_literals\nfrom datetime import timedelta\nimport os\n\nfrom celery import Celery\nfrom kombu import Exchange, Queue\n\n# set the default Django settings module for the 'celery' program.\nos.environ.setdefault('DJANGO_SETTINGS_MODULE', 'shopelectro.settings.local')\n\napp = Celery('shopelectro')\n\n# Exchanges\ndefault_exchange = Exchange('default', type='direct')\nutils_exchange = Exchange('utils', type='direct')\n\n# http://docs.celeryproject.org/en/latest/userguide/tasks.html\ntask_queues = (\n    Queue(\n        name='default',\n        exchange=default_exchange,\n        routing_key='default',\n    ),\n    Queue(\n        name='mail',\n        exchange=utils_exchange,\n        routing_key='utils.mail',\n    ),\n    Queue(\n        name='command',\n        exchange=utils_exchange,\n        routing_key='utils.command',\n    )\n)\n\n# http://docs.celeryproject.org/en/latest/userguide/periodic-tasks.html\nbeat_schedule = {\n    'update-catalog': {\n        'task': 'shopelectro.tasks.update_catalog',\n        'schedule': timedelta(hours=2).total_seconds(),\n    },\n    'update-prices': {\n        'task': 'shopelectro.tasks.update_prices',\n        'schedule': timedelta(hours=1).total_seconds(),\n    },\n    'check-purchase': {\n        'task': 'shopelectro.tasks.check_purchase',\n        'schedule': timedelta(days=1).total_seconds(),\n    },\n}\n\n# http://docs.celeryproject.org/en/master/userguide/routing.html\ntask_routes = {\n    'shopelectro.tasks.update_catalog': {\n        'queue': 'command',\n        'routing_key': 'utils.command',\n        'priority': 30,\n    },\n    'shopelectro.tasks.update_prices': {\n        'queue': 'command',\n        'routing_key': 'utils.command',\n        'priority': 50,\n    },\n    'shopelectro.tasks.check_purchase': {\n        'queue': 'command',\n        'routing_key': 'utils.command',\n        'priority': 20,\n    },\n    'ecommerce.tasks.send_mail': {\n        'queue': 'mail',\n        'routing_key': 'utils.mail',\n        'priority': 50,\n    },\n}\n\n# Using a string here means the worker don't have to serialize\n# the configuration object to child processes.\n# - namespace='CELERY' means all celery-related configuration keys\n#   should have a `CELERY_` prefix.\napp.config_from_object('django.conf:settings', namespace='CELERY')\n\n# http://docs.celeryproject.org/en/latest/userguide/configuration.html\n\nBROCKER_URL = (\n    f'amqp://{os.environ[\"RABBITMQ_DEFAULT_USER\"]}:{os.environ[\"RABBITMQ_DEFAULT_PASS\"]}'\n    f'@{os.environ[\"RABBITMQ_URL\"]}:{os.environ[\"RABBITMQ_PORT\"]}/'\n)\napp.conf.update(\n    broker_url=BROCKER_URL,\n    broker_heartbeat=30,\n    task_acks_late=True,\n    task_default_queue='default',\n    task_default_exchange='default',\n    task_default_routing_key='default',\n    worker_pool_restarts=True,\n    task_routes=task_routes,\n    task_queues=task_queues,\n    beat_schedule=beat_schedule,\n    worker_max_memory_per_child=200000,  # after 250MB will restart\n)\n\n# Load task modules from all registered Django app configs.\napp.autodiscover_tasks()\n", "path": "shopelectro/celery.py"}]}