We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
ClientError (Throttling) in request_cdn_cache_invalidation()
https://sentry.prod.mozaws.net/operations/mdn-prod/issues/6766908/

```
ClientError: An error occurred (Throttling) when calling the CreateInvalidation operation (reached max retries: 4): Rate exceeded
(1 additional frame(s) were not displayed)
...
  File "newrelic/hooks/application_celery.py", line 85, in wrapper
    return wrapped(*args, **kwargs)
  File "celery/app/trace.py", line 648, in __protected_call__
    return self.run(*args, **kwargs)
  File "kuma/api/tasks.py", line 180, in request_cdn_cache_invalidation
    invalidation = client.create_invalidation(
  File "botocore/client.py", line 357, in _api_call
    return self._make_api_call(operation_name, kwargs)
  File "botocore/client.py", line 661, in _make_api_call
    raise error_class(parsed_response, operation_name)

ClientError: An error occurred (Throttling) when calling the CreateInvalidation operation (reached max retries: 4): Rate exceeded
```

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `kuma/api/tasks.py`
Content:
```
1 
2 
3 import json
4 import time
5 
6 import boto3
7 from celery import task
8 from django.conf import settings
9 from django.utils.module_loading import import_string
10 
11 from kuma.core.utils import chunked
12 from kuma.wiki.models import Document
13 
14 from .v1.views import document_api_data, get_content_based_redirect, get_s3_key
15 
16 
17 _s3_resource = None
18 S3_MAX_KEYS_PER_DELETE = 1000
19 
20 
21 def get_s3_resource(config=None):
22     """
23     Get or create the S3 resource. This function is not thread-safe, since it
24     uses the default session, rather than a separate session for each thread.
25     We do not use threads however, so we don't have to handle them.
26     """
27     global _s3_resource
28     if _s3_resource is None:
29         _s3_resource = boto3.resource('s3', config=config)
30     return _s3_resource
31 
32 
33 # The global cloudfront client object to be lazily defined
34 _cloudfront_client = None
35 
36 
37 def get_cloudfront_client(config=None):
38     """
39     Get or create the CloudFront client. This function is not
40     thread-safe, since it uses the default session, rather than
41     a separate session for each thread.
42     We do not use threads however, so we don't have to handle them.
43     """
44     global _cloudfront_client
45     if _cloudfront_client is None:
46         _cloudfront_client = boto3.client('cloudfront', config=config)
47     return _cloudfront_client
48 
49 
50 def get_s3_bucket(config=None):
51     """
52     Get the S3 bucket using the name configured in the environment, otherwise
53     return None.
54     """
55     if not settings.MDN_API_S3_BUCKET_NAME:
56         return None
57     s3 = get_s3_resource(config=config)
58     return s3.Bucket(settings.MDN_API_S3_BUCKET_NAME)
59 
60 
61 @task
62 def unpublish(doc_locale_slug_pairs, log=None, completion_message=None,
63               invalidate_cdn_cache=True):
64     """
65     Delete one or more documents from the S3 bucket serving the document API.
66     """
67     if not log:
68         log = unpublish.get_logger()
69 
70     s3_bucket = get_s3_bucket()
71     if not s3_bucket:
72         log.info('Skipping unpublish of {!r}: no S3 bucket configured'.format(
73             doc_locale_slug_pairs))
74         return
75 
76     keys_to_delete = (get_s3_key(locale=locale, slug=slug)
77                       for locale, slug in doc_locale_slug_pairs)
78 
79     for chunk in chunked(keys_to_delete, S3_MAX_KEYS_PER_DELETE):
80         response = s3_bucket.delete_objects(
81             Delete={
82                 'Objects': [{'Key': key} for key in chunk]
83             }
84         )
85         for info in response.get('Deleted', ()):
86             log.info('Unpublished {}'.format(info['Key']))
87         for info in response.get('Errors', ()):
88             log.error('Unable to unpublish {}: ({}) {}'.format(
89                 info['Key'], info['Code'], info['Message']))
90 
91     if completion_message:
92         log.info(completion_message)
93 
94     if invalidate_cdn_cache:
95         request_cdn_cache_invalidation.delay(doc_locale_slug_pairs)
96 
97 
98 @task
99 def publish(doc_pks, log=None, completion_message=None,
100             invalidate_cdn_cache=True):
101     """
102     Publish one or more documents to the S3 bucket serving the document API.
103     """
104     if not log:
105         log = publish.get_logger()
106 
107     s3_bucket = get_s3_bucket()
108     if not s3_bucket:
109         log.info(
110             'Skipping publish of {!r}: no S3 bucket configured'.format(doc_pks))
111         return
112 
113     if invalidate_cdn_cache:
114         # Use this to turn the document IDs into pairs of (locale, slug).
115         doc_locale_slug_pairs = []
116 
117     for pk in doc_pks:
118         try:
119             doc = Document.objects.get(pk=pk)
120         except Document.DoesNotExist:
121             log.error('Document with pk={} does not exist'.format(pk))
122             continue
123 
124         if invalidate_cdn_cache:
125             # Build up this list for the benefit of triggering a
126             # CDN cache invalidation.
127             doc_locale_slug_pairs.append((doc.locale, doc.slug))
128 
129         kwargs = dict(
130             ACL='public-read',
131             Key=get_s3_key(doc),
132             ContentType='application/json',
133             ContentLanguage=doc.locale,
134         )
135         redirect = get_content_based_redirect(doc)
136         if redirect:
137             redirect_url, is_redirect_to_document = redirect
138             if is_redirect_to_document:
139                 kwargs.update(WebsiteRedirectLocation=redirect_url)
140             data = document_api_data(redirect_url=redirect_url)
141             kwargs.update(Body=json.dumps(data))
142         else:
143             data = document_api_data(doc)
144             kwargs.update(Body=json.dumps(data))
145         s3_object = s3_bucket.put_object(**kwargs)
146         log.info('Published {!r}'.format(s3_object))
147 
148     if completion_message:
149         log.info(completion_message)
150 
151     if invalidate_cdn_cache and doc_locale_slug_pairs:
152         request_cdn_cache_invalidation.delay(doc_locale_slug_pairs)
153 
154 
155 @task
156 def request_cdn_cache_invalidation(doc_locale_slug_pairs, log=None):
157     """
158     Trigger an attempt to purge the given documents from one or more
159     of the configured CloudFront distributions.
160     """
161     if not log:
162         log = request_cdn_cache_invalidation.get_logger()
163 
164     client = get_cloudfront_client()
165     for label, conf in settings.MDN_CLOUDFRONT_DISTRIBUTIONS.items():
166         if not conf['id']:
167             log.info('No Distribution ID available for CloudFront {!r}'.format(
168                 label
169             ))
170             continue
171         transform_function = import_string(conf['transform_function'])
172         paths = (
173             transform_function(locale, slug)
174             for locale, slug in doc_locale_slug_pairs
175         )
176         # In case the transform function decided to "opt-out" on a particular
177         # (locale, slug) it might return a falsy value.
178         paths = [x for x in paths if x]
179         if paths:
180             invalidation = client.create_invalidation(
181                 DistributionId=conf['id'],
182                 InvalidationBatch={
183                     'Paths': {
184                         'Quantity': len(paths),
185                         'Items': paths
186                     },
187                     # The 'CallerReference' just needs to be a unique string.
188                     # By using a timestamp we get slightly more information
189                     # than using a UUID or a random string. But it needs to
190                     # be sufficiently "different" that's why we use 6
191                     # significant figures to avoid the unlikely chance that
192                     # this code gets executed concurrently within a small
193                     # time window.
194                     'CallerReference': '{:.6f}'.format(time.time())
195                 }
196             )
197             log.info(
198                 'Issued cache invalidation for {!r} in {} distribution'
199                 ' (received with {})'.format(
200                     paths,
201                     label,
202                     invalidation['ResponseMetadata']['HTTPStatusCode']
203                 )
204             )
205
```
--- 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()

```

diff --git a/kuma/api/tasks.py b/kuma/api/tasks.py
--- a/kuma/api/tasks.py
+++ b/kuma/api/tasks.py
@@ -4,9 +4,11 @@
 import time
 
 import boto3
+from botocore.exceptions import ClientError
 from celery import task
 from django.conf import settings
 from django.utils.module_loading import import_string
+from redo import retriable
 
 from kuma.core.utils import chunked
 from kuma.wiki.models import Document
@@ -153,6 +155,7 @@
 
 
 @task
+@retriable(retry_exceptions=(ClientError,))
 def request_cdn_cache_invalidation(doc_locale_slug_pairs, log=None):
     """
     Trigger an attempt to purge the given documents from one or more

{"golden_diff": "diff --git a/kuma/api/tasks.py b/kuma/api/tasks.py\n--- a/kuma/api/tasks.py\n+++ b/kuma/api/tasks.py\n@@ -4,9 +4,11 @@\n import time\n \n import boto3\n+from botocore.exceptions import ClientError\n from celery import task\n from django.conf import settings\n from django.utils.module_loading import import_string\n+from redo import retriable\n \n from kuma.core.utils import chunked\n from kuma.wiki.models import Document\n@@ -153,6 +155,7 @@\n \n \n @task\n+@retriable(retry_exceptions=(ClientError,))\n def request_cdn_cache_invalidation(doc_locale_slug_pairs, log=None):\n     \"\"\"\n     Trigger an attempt to purge the given documents from one or more\n", "issue": "ClientError (Throttling) in request_cdn_cache_invalidation()\nhttps://sentry.prod.mozaws.net/operations/mdn-prod/issues/6766908/\n\n```\nClientError: An error occurred (Throttling) when calling the CreateInvalidation operation (reached max retries: 4): Rate exceeded\n(1 additional frame(s) were not displayed)\n...\n  File \"newrelic/hooks/application_celery.py\", line 85, in wrapper\n    return wrapped(*args, **kwargs)\n  File \"celery/app/trace.py\", line 648, in __protected_call__\n    return self.run(*args, **kwargs)\n  File \"kuma/api/tasks.py\", line 180, in request_cdn_cache_invalidation\n    invalidation = client.create_invalidation(\n  File \"botocore/client.py\", line 357, in _api_call\n    return self._make_api_call(operation_name, kwargs)\n  File \"botocore/client.py\", line 661, in _make_api_call\n    raise error_class(parsed_response, operation_name)\n\nClientError: An error occurred (Throttling) when calling the CreateInvalidation operation (reached max retries: 4): Rate exceeded\n```\n", "before_files": [{"content": "\n\nimport json\nimport time\n\nimport boto3\nfrom celery import task\nfrom django.conf import settings\nfrom django.utils.module_loading import import_string\n\nfrom kuma.core.utils import chunked\nfrom kuma.wiki.models import Document\n\nfrom .v1.views import document_api_data, get_content_based_redirect, get_s3_key\n\n\n_s3_resource = None\nS3_MAX_KEYS_PER_DELETE = 1000\n\n\ndef get_s3_resource(config=None):\n    \"\"\"\n    Get or create the S3 resource. This function is not thread-safe, since it\n    uses the default session, rather than a separate session for each thread.\n    We do not use threads however, so we don't have to handle them.\n    \"\"\"\n    global _s3_resource\n    if _s3_resource is None:\n        _s3_resource = boto3.resource('s3', config=config)\n    return _s3_resource\n\n\n# The global cloudfront client object to be lazily defined\n_cloudfront_client = None\n\n\ndef get_cloudfront_client(config=None):\n    \"\"\"\n    Get or create the CloudFront client. This function is not\n    thread-safe, since it uses the default session, rather than\n    a separate session for each thread.\n    We do not use threads however, so we don't have to handle them.\n    \"\"\"\n    global _cloudfront_client\n    if _cloudfront_client is None:\n        _cloudfront_client = boto3.client('cloudfront', config=config)\n    return _cloudfront_client\n\n\ndef get_s3_bucket(config=None):\n    \"\"\"\n    Get the S3 bucket using the name configured in the environment, otherwise\n    return None.\n    \"\"\"\n    if not settings.MDN_API_S3_BUCKET_NAME:\n        return None\n    s3 = get_s3_resource(config=config)\n    return s3.Bucket(settings.MDN_API_S3_BUCKET_NAME)\n\n\n@task\ndef unpublish(doc_locale_slug_pairs, log=None, completion_message=None,\n              invalidate_cdn_cache=True):\n    \"\"\"\n    Delete one or more documents from the S3 bucket serving the document API.\n    \"\"\"\n    if not log:\n        log = unpublish.get_logger()\n\n    s3_bucket = get_s3_bucket()\n    if not s3_bucket:\n        log.info('Skipping unpublish of {!r}: no S3 bucket configured'.format(\n            doc_locale_slug_pairs))\n        return\n\n    keys_to_delete = (get_s3_key(locale=locale, slug=slug)\n                      for locale, slug in doc_locale_slug_pairs)\n\n    for chunk in chunked(keys_to_delete, S3_MAX_KEYS_PER_DELETE):\n        response = s3_bucket.delete_objects(\n            Delete={\n                'Objects': [{'Key': key} for key in chunk]\n            }\n        )\n        for info in response.get('Deleted', ()):\n            log.info('Unpublished {}'.format(info['Key']))\n        for info in response.get('Errors', ()):\n            log.error('Unable to unpublish {}: ({}) {}'.format(\n                info['Key'], info['Code'], info['Message']))\n\n    if completion_message:\n        log.info(completion_message)\n\n    if invalidate_cdn_cache:\n        request_cdn_cache_invalidation.delay(doc_locale_slug_pairs)\n\n\n@task\ndef publish(doc_pks, log=None, completion_message=None,\n            invalidate_cdn_cache=True):\n    \"\"\"\n    Publish one or more documents to the S3 bucket serving the document API.\n    \"\"\"\n    if not log:\n        log = publish.get_logger()\n\n    s3_bucket = get_s3_bucket()\n    if not s3_bucket:\n        log.info(\n            'Skipping publish of {!r}: no S3 bucket configured'.format(doc_pks))\n        return\n\n    if invalidate_cdn_cache:\n        # Use this to turn the document IDs into pairs of (locale, slug).\n        doc_locale_slug_pairs = []\n\n    for pk in doc_pks:\n        try:\n            doc = Document.objects.get(pk=pk)\n        except Document.DoesNotExist:\n            log.error('Document with pk={} does not exist'.format(pk))\n            continue\n\n        if invalidate_cdn_cache:\n            # Build up this list for the benefit of triggering a\n            # CDN cache invalidation.\n            doc_locale_slug_pairs.append((doc.locale, doc.slug))\n\n        kwargs = dict(\n            ACL='public-read',\n            Key=get_s3_key(doc),\n            ContentType='application/json',\n            ContentLanguage=doc.locale,\n        )\n        redirect = get_content_based_redirect(doc)\n        if redirect:\n            redirect_url, is_redirect_to_document = redirect\n            if is_redirect_to_document:\n                kwargs.update(WebsiteRedirectLocation=redirect_url)\n            data = document_api_data(redirect_url=redirect_url)\n            kwargs.update(Body=json.dumps(data))\n        else:\n            data = document_api_data(doc)\n            kwargs.update(Body=json.dumps(data))\n        s3_object = s3_bucket.put_object(**kwargs)\n        log.info('Published {!r}'.format(s3_object))\n\n    if completion_message:\n        log.info(completion_message)\n\n    if invalidate_cdn_cache and doc_locale_slug_pairs:\n        request_cdn_cache_invalidation.delay(doc_locale_slug_pairs)\n\n\n@task\ndef request_cdn_cache_invalidation(doc_locale_slug_pairs, log=None):\n    \"\"\"\n    Trigger an attempt to purge the given documents from one or more\n    of the configured CloudFront distributions.\n    \"\"\"\n    if not log:\n        log = request_cdn_cache_invalidation.get_logger()\n\n    client = get_cloudfront_client()\n    for label, conf in settings.MDN_CLOUDFRONT_DISTRIBUTIONS.items():\n        if not conf['id']:\n            log.info('No Distribution ID available for CloudFront {!r}'.format(\n                label\n            ))\n            continue\n        transform_function = import_string(conf['transform_function'])\n        paths = (\n            transform_function(locale, slug)\n            for locale, slug in doc_locale_slug_pairs\n        )\n        # In case the transform function decided to \"opt-out\" on a particular\n        # (locale, slug) it might return a falsy value.\n        paths = [x for x in paths if x]\n        if paths:\n            invalidation = client.create_invalidation(\n                DistributionId=conf['id'],\n                InvalidationBatch={\n                    'Paths': {\n                        'Quantity': len(paths),\n                        'Items': paths\n                    },\n                    # The 'CallerReference' just needs to be a unique string.\n                    # By using a timestamp we get slightly more information\n                    # than using a UUID or a random string. But it needs to\n                    # be sufficiently \"different\" that's why we use 6\n                    # significant figures to avoid the unlikely chance that\n                    # this code gets executed concurrently within a small\n                    # time window.\n                    'CallerReference': '{:.6f}'.format(time.time())\n                }\n            )\n            log.info(\n                'Issued cache invalidation for {!r} in {} distribution'\n                ' (received with {})'.format(\n                    paths,\n                    label,\n                    invalidation['ResponseMetadata']['HTTPStatusCode']\n                )\n            )\n", "path": "kuma/api/tasks.py"}], "after_files": [{"content": "\n\nimport json\nimport time\n\nimport boto3\nfrom botocore.exceptions import ClientError\nfrom celery import task\nfrom django.conf import settings\nfrom django.utils.module_loading import import_string\nfrom redo import retriable\n\nfrom kuma.core.utils import chunked\nfrom kuma.wiki.models import Document\n\nfrom .v1.views import document_api_data, get_content_based_redirect, get_s3_key\n\n\n_s3_resource = None\nS3_MAX_KEYS_PER_DELETE = 1000\n\n\ndef get_s3_resource(config=None):\n    \"\"\"\n    Get or create the S3 resource. This function is not thread-safe, since it\n    uses the default session, rather than a separate session for each thread.\n    We do not use threads however, so we don't have to handle them.\n    \"\"\"\n    global _s3_resource\n    if _s3_resource is None:\n        _s3_resource = boto3.resource('s3', config=config)\n    return _s3_resource\n\n\n# The global cloudfront client object to be lazily defined\n_cloudfront_client = None\n\n\ndef get_cloudfront_client(config=None):\n    \"\"\"\n    Get or create the CloudFront client. This function is not\n    thread-safe, since it uses the default session, rather than\n    a separate session for each thread.\n    We do not use threads however, so we don't have to handle them.\n    \"\"\"\n    global _cloudfront_client\n    if _cloudfront_client is None:\n        _cloudfront_client = boto3.client('cloudfront', config=config)\n    return _cloudfront_client\n\n\ndef get_s3_bucket(config=None):\n    \"\"\"\n    Get the S3 bucket using the name configured in the environment, otherwise\n    return None.\n    \"\"\"\n    if not settings.MDN_API_S3_BUCKET_NAME:\n        return None\n    s3 = get_s3_resource(config=config)\n    return s3.Bucket(settings.MDN_API_S3_BUCKET_NAME)\n\n\n@task\ndef unpublish(doc_locale_slug_pairs, log=None, completion_message=None,\n              invalidate_cdn_cache=True):\n    \"\"\"\n    Delete one or more documents from the S3 bucket serving the document API.\n    \"\"\"\n    if not log:\n        log = unpublish.get_logger()\n\n    s3_bucket = get_s3_bucket()\n    if not s3_bucket:\n        log.info('Skipping unpublish of {!r}: no S3 bucket configured'.format(\n            doc_locale_slug_pairs))\n        return\n\n    keys_to_delete = (get_s3_key(locale=locale, slug=slug)\n                      for locale, slug in doc_locale_slug_pairs)\n\n    for chunk in chunked(keys_to_delete, S3_MAX_KEYS_PER_DELETE):\n        response = s3_bucket.delete_objects(\n            Delete={\n                'Objects': [{'Key': key} for key in chunk]\n            }\n        )\n        for info in response.get('Deleted', ()):\n            log.info('Unpublished {}'.format(info['Key']))\n        for info in response.get('Errors', ()):\n            log.error('Unable to unpublish {}: ({}) {}'.format(\n                info['Key'], info['Code'], info['Message']))\n\n    if completion_message:\n        log.info(completion_message)\n\n    if invalidate_cdn_cache:\n        request_cdn_cache_invalidation.delay(doc_locale_slug_pairs)\n\n\n@task\ndef publish(doc_pks, log=None, completion_message=None,\n            invalidate_cdn_cache=True):\n    \"\"\"\n    Publish one or more documents to the S3 bucket serving the document API.\n    \"\"\"\n    if not log:\n        log = publish.get_logger()\n\n    s3_bucket = get_s3_bucket()\n    if not s3_bucket:\n        log.info(\n            'Skipping publish of {!r}: no S3 bucket configured'.format(doc_pks))\n        return\n\n    if invalidate_cdn_cache:\n        # Use this to turn the document IDs into pairs of (locale, slug).\n        doc_locale_slug_pairs = []\n\n    for pk in doc_pks:\n        try:\n            doc = Document.objects.get(pk=pk)\n        except Document.DoesNotExist:\n            log.error('Document with pk={} does not exist'.format(pk))\n            continue\n\n        if invalidate_cdn_cache:\n            # Build up this list for the benefit of triggering a\n            # CDN cache invalidation.\n            doc_locale_slug_pairs.append((doc.locale, doc.slug))\n\n        kwargs = dict(\n            ACL='public-read',\n            Key=get_s3_key(doc),\n            ContentType='application/json',\n            ContentLanguage=doc.locale,\n        )\n        redirect = get_content_based_redirect(doc)\n        if redirect:\n            redirect_url, is_redirect_to_document = redirect\n            if is_redirect_to_document:\n                kwargs.update(WebsiteRedirectLocation=redirect_url)\n            data = document_api_data(redirect_url=redirect_url)\n            kwargs.update(Body=json.dumps(data))\n        else:\n            data = document_api_data(doc)\n            kwargs.update(Body=json.dumps(data))\n        s3_object = s3_bucket.put_object(**kwargs)\n        log.info('Published {!r}'.format(s3_object))\n\n    if completion_message:\n        log.info(completion_message)\n\n    if invalidate_cdn_cache and doc_locale_slug_pairs:\n        request_cdn_cache_invalidation.delay(doc_locale_slug_pairs)\n\n\n@task\n@retriable(retry_exceptions=(ClientError,))\ndef request_cdn_cache_invalidation(doc_locale_slug_pairs, log=None):\n    \"\"\"\n    Trigger an attempt to purge the given documents from one or more\n    of the configured CloudFront distributions.\n    \"\"\"\n    if not log:\n        log = request_cdn_cache_invalidation.get_logger()\n\n    client = get_cloudfront_client()\n    for label, conf in settings.MDN_CLOUDFRONT_DISTRIBUTIONS.items():\n        if not conf['id']:\n            log.info('No Distribution ID available for CloudFront {!r}'.format(\n                label\n            ))\n            continue\n        transform_function = import_string(conf['transform_function'])\n        paths = (\n            transform_function(locale, slug)\n            for locale, slug in doc_locale_slug_pairs\n        )\n        # In case the transform function decided to \"opt-out\" on a particular\n        # (locale, slug) it might return a falsy value.\n        paths = [x for x in paths if x]\n        if paths:\n            invalidation = client.create_invalidation(\n                DistributionId=conf['id'],\n                InvalidationBatch={\n                    'Paths': {\n                        'Quantity': len(paths),\n                        'Items': paths\n                    },\n                    # The 'CallerReference' just needs to be a unique string.\n                    # By using a timestamp we get slightly more information\n                    # than using a UUID or a random string. But it needs to\n                    # be sufficiently \"different\" that's why we use 6\n                    # significant figures to avoid the unlikely chance that\n                    # this code gets executed concurrently within a small\n                    # time window.\n                    'CallerReference': '{:.6f}'.format(time.time())\n                }\n            )\n            log.info(\n                'Issued cache invalidation for {!r} in {} distribution'\n                ' (received with {})'.format(\n                    paths,\n                    label,\n                    invalidation['ResponseMetadata']['HTTPStatusCode']\n                )\n            )\n", "path": "kuma/api/tasks.py"}]}