Skip to content

Commit b9aa889

Browse files
authored
Cover long-running jobs in the deferrable BigQuery check system test (#74356)
The deferrable value and interval checks in the async BigQuery system test only ran trivial COUNT(*) queries, so their jobs were DONE before the trigger's first poll. The regression fixed in #74305, where BigQueryValueCheckTrigger and BigQueryIntervalCheckTrigger failed with "Job running" while the job was still RUNNING (#73981), could therefore never show up in the system test. Add a view backed by a JavaScript UDF that keeps a query RUNNING for tens of seconds and run both deferrable checks against it. The view only reads the existing two-row table, so each check job is billed at BigQuery's 10 MB minimum.
1 parent e009c11 commit b9aa889

1 file changed

Lines changed: 53 additions & 1 deletion

File tree

‎providers/google/tests/system/google/cloud/bigquery/example_bigquery_queries_async.py‎

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,26 @@
100100
}
101101
}
102102

103+
SLOW_VIEW_NAME = f"view_{DAG_ID}_{ENV_ID}_slow".replace("-", "_")
104+
105+
# The JavaScript UDF spins for a fixed number of iterations per row, which keeps a query over the view
106+
# RUNNING for tens of seconds, i.e. across several poll intervals of the deferrable check operators
107+
# (#73981). `CURRENT_TIMESTAMP()` makes the view non-deterministic, so BigQuery never serves a repeated
108+
# check from the query cache. Nothing here scans more than the two-row table, so the jobs are billed at
109+
# the 10 MB minimum.
110+
CREATE_SLOW_VIEW_QUERY = f"""
111+
CREATE OR REPLACE FUNCTION `{DATASET_NAME}.slow_ds`(ds STRING) RETURNS STRING LANGUAGE js AS r'''
112+
let acc = 0;
113+
for (let i = 0; i < 500000000; i++) {{
114+
acc = (acc * 31 + i) % 1000003;
115+
}}
116+
return acc >= 0 ? ds : null;
117+
''';
118+
CREATE OR REPLACE VIEW `{DATASET_NAME}.{SLOW_VIEW_NAME}` AS
119+
SELECT value, name, `{DATASET_NAME}.slow_ds`(ds) AS ds
120+
FROM `{DATASET_NAME}.{TABLE_NAME_1}`
121+
WHERE CURRENT_TIMESTAMP() IS NOT NULL;
122+
"""
103123

104124
default_args = {
105125
"execution_timeout": timedelta(hours=6),
@@ -262,6 +282,31 @@
262282
deferrable=True,
263283
)
264284

285+
create_slow_view = BigQueryInsertJobOperator(
286+
task_id="create_slow_view",
287+
configuration={"query": {"query": CREATE_SLOW_VIEW_QUERY, "useLegacySql": False}},
288+
location=LOCATION,
289+
)
290+
291+
check_value_long_running = BigQueryValueCheckOperator(
292+
task_id="check_value_long_running",
293+
sql=f"SELECT COUNT(*) FROM {DATASET_NAME}.{SLOW_VIEW_NAME} WHERE ds IS NOT NULL",
294+
pass_value=2,
295+
use_legacy_sql=False,
296+
location=LOCATION,
297+
deferrable=True,
298+
)
299+
300+
check_interval_long_running = BigQueryIntervalCheckOperator(
301+
task_id="check_interval_long_running",
302+
table=f"{DATASET_NAME}.{SLOW_VIEW_NAME}",
303+
days_back=1,
304+
metrics_thresholds={"COUNT(*)": 1.5},
305+
use_legacy_sql=False,
306+
location=LOCATION,
307+
deferrable=True,
308+
)
309+
265310
check_openlineage_events = OpenLineageTestOperator(
266311
task_id="check_openlineage_events",
267312
file_path=str(Path(__file__).parent / "resources" / "openlineage" / "bigquery_queries_async.json"),
@@ -272,7 +317,14 @@
272317
insert_query_job >> get_data >> get_data_result
273318
insert_query_job >> execute_query_save >> bigquery_execute_multi_query
274319
insert_query_job >> execute_long_running_query >> check_value >> check_interval
275-
[check_count, check_interval, bigquery_execute_multi_query, get_data_result] >> delete_dataset
320+
insert_query_job >> create_slow_view >> check_value_long_running >> check_interval_long_running
321+
[
322+
check_count,
323+
check_interval,
324+
check_interval_long_running,
325+
bigquery_execute_multi_query,
326+
get_data_result,
327+
] >> delete_dataset
276328
delete_dataset >> check_openlineage_events
277329

278330
from tests_common.test_utils.watcher import watcher

0 commit comments

Comments
 (0)