|
5 | 5 | import time
|
6 | 6 | import urllib.parse as urlparse
|
7 | 7 | from abc import ABC
|
8 |
| -from collections import deque |
| 8 | +from collections import defaultdict, deque |
9 | 9 | from datetime import datetime
|
10 | 10 | from typing import Any, Iterable, Iterator, List, Mapping, MutableMapping, Optional, Sequence
|
11 | 11 |
|
|
23 | 23 | from facebook_business.exceptions import FacebookRequestError
|
24 | 24 | from source_facebook_marketing.api import API
|
25 | 25 |
|
26 |
| -from .common import FacebookAPIException, JobTimeoutException, batch, deep_merge, retry_pattern |
| 26 | +from .common import FacebookAPIException, JobException, JobTimeoutException, batch, deep_merge, retry_pattern |
27 | 27 |
|
28 | 28 | backoff_policy = retry_pattern(backoff.expo, FacebookRequestError, max_tries=5, factor=5)
|
| 29 | +MAX_JOB_RESTART_TIMES = 6 |
29 | 30 |
|
30 | 31 |
|
31 | 32 | def remove_params_from_url(url: str, params: List[str]) -> str:
|
@@ -291,7 +292,7 @@ class AdsInsights(FBMarketingIncrementalStream):
|
291 | 292 | time_increment = 1
|
292 | 293 |
|
293 | 294 | running_jobs = deque()
|
294 |
| - times_job_restarted = {} |
| 295 | + times_job_restarted = defaultdict(int) |
295 | 296 |
|
296 | 297 | breakdowns = []
|
297 | 298 |
|
@@ -369,31 +370,51 @@ def wait_for_job(self, job, stream_state: Mapping[str, Any] = None) -> AdReportR
|
369 | 370 |
|
370 | 371 | if job["async_status"] == "Job Completed":
|
371 | 372 | return job
|
372 |
| - elif job["async_status"] in ["Job Failed", "Job Skipped"]: |
| 373 | + else: |
373 | 374 | time_range = (job["date_start"], job["date_stop"])
|
374 |
| - if self.times_job_restarted.get(time_range, 0) < 6: |
| 375 | + if self.times_job_restarted[time_range] < MAX_JOB_RESTART_TIMES: |
375 | 376 | params = deep_merge(
|
376 | 377 | {"time_range": {"since": job["date_start"], "until": job["date_stop"]}},
|
377 | 378 | self.request_params(stream_state=stream_state),
|
378 | 379 | )
|
379 | 380 | restart_job = self._create_insights_job(params)
|
380 | 381 | self.running_jobs.append(restart_job)
|
381 | 382 | self.times_job_restarted[time_range] += 1
|
382 |
| - elif job["async_status"] == "Job Failed": |
383 |
| - raise JobTimeoutException(f"AdReportRun {job} failed after {runtime.in_seconds()} seconds.") |
384 |
| - elif job["async_status"] == "Job Skipped": |
385 |
| - raise JobTimeoutException(f"AdReportRun {job} skipped after {runtime.in_seconds()} seconds.") |
386 |
| - |
387 |
| - if runtime > self.MAX_WAIT_TO_START and job_progress_pct == 0: |
388 |
| - raise JobTimeoutException( |
389 |
| - f"AdReportRun {job} did not start after {runtime.in_seconds()} seconds." |
390 |
| - f" This is an intermittent error which may be fixed by retrying the job. Aborting." |
391 |
| - ) |
392 |
| - elif runtime > self.MAX_WAIT_TO_FINISH: |
393 |
| - raise JobTimeoutException( |
394 |
| - f"AdReportRun {job} did not finish after {runtime.in_seconds()} seconds." |
395 |
| - f" This is an intermittent error which may be fixed by retrying the job. Aborting." |
396 |
| - ) |
| 383 | + else: |
| 384 | + error_msg = """ |
| 385 | + AdReportRun job with id={id} {error_type}. |
| 386 | + Details: report_run_id={report_run_id}, |
| 387 | + date_start={date_start}, date_stop={date_stop} |
| 388 | + """ |
| 389 | + if job["async_status"] == "Job Failed": |
| 390 | + raise JobException( |
| 391 | + error_msg.format( |
| 392 | + error_type="failed", |
| 393 | + report_run_id=job["report_run_id"], |
| 394 | + date_start=job["date_start"], |
| 395 | + date_stop=job["date_stop"], |
| 396 | + ) |
| 397 | + ) |
| 398 | + elif job["async_status"] == "Job Skipped": |
| 399 | + raise JobException( |
| 400 | + error_msg.format( |
| 401 | + error_type="failed", |
| 402 | + report_run_id=job["report_run_id"], |
| 403 | + date_start=job["date_start"], |
| 404 | + date_stop=job["date_stop"], |
| 405 | + ) |
| 406 | + ) |
| 407 | + |
| 408 | + if runtime > self.MAX_WAIT_TO_START and job_progress_pct == 0: |
| 409 | + raise JobTimeoutException( |
| 410 | + f"AdReportRun {job} did not start after {runtime.in_seconds()} seconds." |
| 411 | + f" This is an intermittent error which may be fixed by retrying the job. Aborting." |
| 412 | + ) |
| 413 | + elif runtime > self.MAX_WAIT_TO_FINISH: |
| 414 | + raise JobTimeoutException( |
| 415 | + f"AdReportRun {job} did not finish after {runtime.in_seconds()} seconds." |
| 416 | + f" This is an intermittent error which may be fixed by retrying the job. Aborting." |
| 417 | + ) |
397 | 418 | self.logger.info(f"Sleeping {sleep_seconds} seconds while waiting for AdReportRun: {job_id} to complete")
|
398 | 419 | time.sleep(sleep_seconds)
|
399 | 420 | if sleep_seconds < self.MAX_ASYNC_SLEEP.in_seconds():
|
|
0 commit comments