Skip to content

Commit 03509ec

Browse files
authored
issue two purges for fastly surrogate keys (#12771)
* issue two purges for fastly surrogate keys https://developer.fastly.com/learning/concepts/purging/#race-conditions states there are some race conditions we may be running into with shielding enabled. ref: #12214 * 🖤 * test for second purge failure
1 parent e56b3fb commit 03509ec

File tree

2 files changed

+60
-2
lines changed

2 files changed

+60
-2
lines changed

tests/unit/cache/origin/test_fastly.py

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@
1010
# See the License for the specific language governing permissions and
1111
# limitations under the License.
1212

13+
import itertools
14+
1315
import celery.exceptions
1416
import pretend
1517
import pytest
@@ -188,9 +190,17 @@ def test_purge_key_ok(self, monkeypatch):
188190
"Fastly-Key": "an api key",
189191
"Fastly-Soft-Purge": "1",
190192
},
191-
)
193+
),
194+
pretend.call(
195+
"https://api.fastly.com/service/the-service-id/purge/one",
196+
headers={
197+
"Accept": "application/json",
198+
"Fastly-Key": "an api key",
199+
"Fastly-Soft-Purge": "1",
200+
},
201+
),
192202
]
193-
assert response.raise_for_status.calls == [pretend.call()]
203+
assert response.raise_for_status.calls == [pretend.call(), pretend.call()]
194204

195205
@pytest.mark.parametrize("result", [{"status": "fail"}, {}])
196206
def test_purge_key_unsuccessful(self, monkeypatch, result):
@@ -218,3 +228,42 @@ def test_purge_key_unsuccessful(self, monkeypatch, result):
218228
)
219229
]
220230
assert response.raise_for_status.calls == [pretend.call()]
231+
232+
@pytest.mark.parametrize(
233+
"result", [[{"status": "ok"}, {"status": "fail"}], [{"status": "ok"}, {}]]
234+
)
235+
def test_purge_key_second_unsuccessful(self, monkeypatch, result):
236+
cacher = fastly.FastlyCache(
237+
api_key="an api key", service_id="the-service-id", purger=None
238+
)
239+
240+
_result = itertools.cycle(result)
241+
response = pretend.stub(
242+
raise_for_status=pretend.call_recorder(lambda: None),
243+
json=lambda: next(_result),
244+
)
245+
requests_post = pretend.call_recorder(lambda *a, **kw: response)
246+
monkeypatch.setattr(requests, "post", requests_post)
247+
248+
with pytest.raises(fastly.UnsuccessfulPurgeError):
249+
cacher.purge_key("one")
250+
251+
assert requests_post.calls == [
252+
pretend.call(
253+
"https://api.fastly.com/service/the-service-id/purge/one",
254+
headers={
255+
"Accept": "application/json",
256+
"Fastly-Key": "an api key",
257+
"Fastly-Soft-Purge": "1",
258+
},
259+
),
260+
pretend.call(
261+
"https://api.fastly.com/service/the-service-id/purge/one",
262+
headers={
263+
"Accept": "application/json",
264+
"Fastly-Key": "an api key",
265+
"Fastly-Soft-Purge": "1",
266+
},
267+
),
268+
]
269+
assert response.raise_for_status.calls == [pretend.call(), pretend.call()]

warehouse/cache/origin/fastly.py

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
# See the License for the specific language governing permissions and
1111
# limitations under the License.
1212

13+
import time
1314
import urllib.parse
1415

1516
import requests
@@ -106,3 +107,11 @@ def purge_key(self, key):
106107

107108
if resp.json().get("status") != "ok":
108109
raise UnsuccessfulPurgeError(f"Could not purge {key!r}")
110+
111+
time.sleep(2)
112+
113+
resp = requests.post(url, headers=headers)
114+
resp.raise_for_status()
115+
116+
if resp.json().get("status") != "ok":
117+
raise UnsuccessfulPurgeError(f"Could not double purge {key!r}")

0 commit comments

Comments
 (0)