Với mỗi trạng thái terminal không phải COMPLETED: quyết định retry, alert, hay compensate?
# Sync — đơn giản, dùng cho query/readimport requests
response = requests.get(
"https://api/dna/intent/api/v1/network-device",
headers=headers
)
data = response.json() # data ngay lập tức
print(data["response"])
# Async + exponential backoff với jitterimport random, time, requests
defpoll_with_backoff(task_url, headers, max_wait=300):
start = time.time()
delay = 2# initial delay (seconds)while time.time() - start < max_wait:
resp = requests.get(task_url, headers=headers)
resp.raise_for_status()
state = resp.json().get("state")
if state == "COMPLETED":
return resp.json()
if state in ("FAILED", "ABORTED"):
raise RuntimeError(f"Task failed: {resp.json()}")
# Full jitter: tránh thundering herd
sleep_time = min(delay * (1 + random.random()), 30)
time.sleep(sleep_time)
delay = min(delay * 2, 60)
raise TimeoutError(f"Task không complete sau {max_wait}s")
# Idempotency key — tránh duplicate khi retryimport uuid, requests
# Generate ONCE, lưu lại trước khi submit
idem_key = str(uuid.uuid4())
headers = {
"Idempotency-Key": idem_key, # server dedup theo key này"Content-Type": "application/json"
}
# Nếu timeout và retry với CÙNG key → server trả cùng task_id# Không bị tạo duplicate deployment/VM/workflow
response = requests.post(url, headers=headers, json=payload)
task_id = response.json()["executionId"]
# Check-before-act cho API không hỗ trợ idempotency key
existing = requests.get(
f"{base_url}/sites?name={site_name}",
headers=headers
)
if existing.json()["totalCount"] == 0:
create_site(site_name)