From fa6627ce7069983c62c2562ecb65e7de4f82be8f Mon Sep 17 00:00:00 2001 From: Ilya Kreymer Date: Wed, 12 Jun 2024 10:51:35 -0700 Subject: [PATCH] ensure QA configmap is updated for long running QA runs: (#1865) - add a 'expire_at_duration_seconds' which is 75% of actual presign duration time, or <25% remaining until presigned URL actually expires to ensure presigned URLs are updated early than when they actually expire - set cached expireAt time to the renew at time for more frequent updates - update QA configmap in place with updated presigned URLs when expireAt time is reached - mount qa config volume under /tmp/qa/ without subPath to get automatic updates, which crawler will handle - tests: fix qa test typo (from main) - fixes #1864 --- backend/btrixcloud/basecrawls.py | 8 ++++++-- backend/btrixcloud/operator/crawls.py | 27 +++++++++++++++++++++++++-- backend/test/test_qa.py | 2 +- chart/app-templates/crawler.yaml | 5 ++--- chart/templates/operators.yaml | 2 +- 5 files changed, 35 insertions(+), 9 deletions(-) diff --git a/backend/btrixcloud/basecrawls.py b/backend/btrixcloud/basecrawls.py index cf03bdea..5aec6be4 100644 --- a/backend/btrixcloud/basecrawls.py +++ b/backend/btrixcloud/basecrawls.py @@ -64,7 +64,8 @@ class BaseCrawlOps: background_job_ops: BackgroundJobOps page_ops: PageOps - presign_duration: int + presign_duration_seconds: int + expire_at_duration_seconds: int def __init__( self, @@ -95,6 +96,9 @@ class BaseCrawlOps: min(presign_duration_minutes, PRESIGN_MINUTES_MAX) * 60 ) + # renew when <25% of time remaining + self.expire_at_duration_seconds = int(self.presign_duration_seconds * 0.75) + def set_page_ops(self, page_ops): """set page ops reference""" self.page_ops = page_ops @@ -434,7 +438,7 @@ class BaseCrawlOps: print("no files") return [] - delta = timedelta(seconds=self.presign_duration_seconds) + delta = timedelta(seconds=self.expire_at_duration_seconds) out_files = [] diff --git a/backend/btrixcloud/operator/crawls.py b/backend/btrixcloud/operator/crawls.py index 9962c827..e6eee4df 100644 --- a/backend/btrixcloud/operator/crawls.py +++ b/backend/btrixcloud/operator/crawls.py @@ -325,8 +325,15 @@ class CrawlOperator(BaseOperator): qa_source_crawl_id = params["qa_source_crawl_id"] name = f"qa-replay-{qa_source_crawl_id}" - if name in children[CMAP]: - return [children[CMAP][name]] + configmap = children[CMAP].get(name) + if configmap and not self._qa_configmap_update_needed(name, configmap): + metadata = configmap["metadata"] + configmap["metadata"] = { + "name": metadata["name"], + "namespace": metadata["namespace"], + "labels": metadata["labels"], + } + return [configmap] crawl_replay = await self.crawl_ops.get_internal_crawl_out(qa_source_crawl_id) @@ -364,6 +371,22 @@ class CrawlOperator(BaseOperator): return self.load_from_yaml("crawler.yaml", params) + def _qa_configmap_update_needed(self, name, configmap): + try: + now = dt_now() + resources = json.loads(configmap["data"]["qa-config.json"])["resources"] + for resource in resources: + expire_at = datetime.fromisoformat(resource["expireAt"]) + if expire_at <= now: + print(f"Refreshing QA configmap for QA run: {name}") + return True + + # pylint: disable=broad-exception-caught + except Exception as e: + print(e) + + return False + # pylint: disable=too-many-arguments async def _resolve_scale( self, diff --git a/backend/test/test_qa.py b/backend/test/test_qa.py index 85f09e1d..e9861b31 100644 --- a/backend/test/test_qa.py +++ b/backend/test/test_qa.py @@ -383,7 +383,7 @@ def test_run_qa_not_running( count = 0 while count < MAX_ATTEMPTS: r = requests.get( - f"{API_PREFIX}/orgs/{default_org_id}/crawls/{crawler_crawl_id}/activeQA", + f"{API_PREFIX}/orgs/{default_org_id}/crawls/{crawler_crawl_id}/qa/activeQA", headers=crawler_auth_headers, ) data = r.json() diff --git a/chart/app-templates/crawler.yaml b/chart/app-templates/crawler.yaml index acd6e1b9..6dc618d0 100644 --- a/chart/app-templates/crawler.yaml +++ b/chart/app-templates/crawler.yaml @@ -124,7 +124,7 @@ spec: - {{ redis_url }} {% if qa_source_crawl_id %} - --qaSource - - /tmp/qa-config.json + - /tmp/qa/qa-config.json {% elif profile_filename %} - --profile - "@{{ profile_filename }}" @@ -137,8 +137,7 @@ spec: {% if qa_source_crawl_id %} - name: qa-config - mountPath: /tmp/qa-config.json - subPath: qa-config.json + mountPath: /tmp/qa/ readOnly: True {% endif %} diff --git a/chart/templates/operators.yaml b/chart/templates/operators.yaml index b7126edb..92e6a3a8 100644 --- a/chart/templates/operators.yaml +++ b/chart/templates/operators.yaml @@ -23,7 +23,7 @@ spec: - apiVersion: v1 resource: configmaps updateStrategy: - method: OnDelete + method: InPlace hooks: sync: