AI Hình Ảnh
API & tự động hoá hình ảnh

Xử lý lỗi 503 và Retry-After khi gọi API tạo hình ảnh, kèm hàng đợi

13/10/2026 · 5 phút đọc · AI Hình Ảnh

Phân biệt lỗi nên thử lại và lỗi phải dừng, vòng thử lại có giãn cách theo Retry-After, và một hàng đợi SQLite nhỏ giúp chạy hàng trăm lượt vẽ không mất việc nào.

Xử lý lỗi 503 và Retry-After khi gọi API tạo hình ảnh, kèm hàng đợi

Lần đầu gọi API AI Hình Ảnh trong vòng lặp hai trăm dòng, nhiều người gặp cùng một cảnh: chạy êm được ba mươi lượt, rồi một tràng mã 503, rồi đoạn mã dừng hẳn vì không ai bắt lỗi. Hoặc tệ hơn: đoạn mã thử lại liên tục không nghỉ, càng làm máy vẽ bận thêm. Bài này đưa ra cách xử lý lỗi đúng với API này, kèm mã Python chạy được và một hàng đợi nhỏ bằng SQLite để việc chạy hàng loạt không bao giờ mất dòng nào.

Vì sao có 503

Máy vẽ của AI Hình Ảnh đặt tại Việt Nam và dùng chung với các dịch vụ khác của hệ AI Đỉnh. Mỗi lượt gọi API là đồng bộ: máy chủ nhận yêu cầu, vẽ, rồi trả hình ảnh trong cùng một kết nối, chờ tối đa khoảng 90 giây. Vì vậy số lượt đang xử lý cùng lúc có giới hạn. Khi vượt giới hạn, hoặc máy vẽ đang nhận việc từ nơi khác, API trả 503 kèm header Retry-After cho biết nên chờ bao nhiêu giây.

503 là lỗi tạm thời và bình thường. Hệ thống của bạn phải coi nó như "đèn đỏ", không phải "đường cụt".

Phân loại lỗi: thử lại hay dừng

MãNghĩaThử lại?Việc cần làm
200Thành công (có thể ít hình ảnh hơn n)—Lưu những hình ảnh nhận được
400Tham số sai, thiếu promptKhôngGhi lỗi vào dòng đó, sửa dữ liệu
401Thiếu khoá, sai khoá, khoá đã tắtKhôngDừng toàn bộ hàng đợi, kiểm tra khoá
402Không đủ điểmKhôngDừng toàn bộ hàng đợi, nạp điểm
503Máy vẽ bậnCóChờ đúng Retry-After, cộng thêm vài giây ngẫu nhiên
Lỗi 5xx khácLỗi phía máy chủCó, ít lầnChờ lâu hơn, quá số lần thì đánh dấu lỗi
Hết giờ, mất mạng phía bạnKết nối đứtCó, cẩn thậnGhi lại để đối chiếu điểm (xem dưới)

Hai mã 401 và 402 đặc biệt: chúng không phải lỗi của một dòng mà của cả tài khoản. Thử lại dòng tiếp theo cũng sẽ lỗi y hệt. Dừng ngay, báo người phụ trách.

Trường hợp 200 nhưng thiếu hình ảnh

Khi gửi n lớn với hạng chậm, máy vẽ từng hình ảnh lần lượt trong khoảng 90 giây. Không kịp thì trả về số hình ảnh đã vẽ được, phần còn lại hoàn điểm. Đây không phải lỗi, nhưng mã của bạn phải đếm len(data) thực nhận và, nếu cần đủ số, xếp thêm một lượt cho phần thiếu. usage.images và usage.credits trong kết quả cho biết chính xác số hình ảnh và số điểm đã tính.

Vòng thử lại đúng cách

Ba nguyên tắc:

  1. Tôn trọng Retry-After. Máy chủ biết rõ hơn bạn khi nào rảnh.
  2. Thêm độ lệch ngẫu nhiên. Nếu bạn chạy vài tiến trình, chúng không được cùng thức dậy một giây rồi lại cùng nhận 503.
  3. Giới hạn số lần. Sau năm lần, đánh dấu dòng là lỗi tạm thời và đi tiếp, để chạy lại sau.

```python
import os
import random
import time

import requests

URL = "https://aihinhanh.com/v1/images/generations"
KEY = os.environ["AHN_KEY"] # ahn_XXXX

class LoiDungHan(Exception):
"""401, 402: lỗi của cả tài khoản, phải dừng hàng đợi."""

class LoiDuLieu(Exception):
"""400: lỗi của riêng dòng này, sửa dữ liệu rồi chạy lại."""

class LoiTamThoi(Exception):
"""Thử đủ số lần mà vẫn bận: để lượt sau."""

def ve(payload: dict, so_lan: int = 5) -> dict:
cho_mac_dinh = 15
loi_cuoi = ""
for lan in range(1, so_lan + 1):
retry_after = None
try:
r = requests.post(
URL,
json=payload,
headers={"Authorization": f"Bearer {KEY}"},
timeout=120,
)
except requests.RequestException as e:
loi_cuoi = f"mạng: {e}"
else:
if r.status_code == 200:
return r.json()
try:
thong_bao = r.json().get("error", {}).get("message", "")
except ValueError:
thong_bao = r.text[:200]
if r.status_code in (401, 402):
raise LoiDungHan(f"{r.status_code}: {thong_bao}")
if r.status_code == 400:
raise LoiDuLieu(thong_bao)
loi_cuoi = f"{r.status_code}: {thong_bao}"
retry_after = r.headers.get("Retry-After")

if retry_after and retry_after.isdigit():
cho = int(retry_after)
else:
cho = cho_mac_dinh * (2 ** (lan - 1)) # 15, 30, 60, 120...
cho = min(cho, 300) + random.uniform(0, 6)
print(f" lần {lan} lỗi ({loi_cuoi}), chờ {cho:.0f}s")
time.sleep(cho)
raise LoiTamThoi(loi_cuoi)
```

Hàm trả về nguyên kết quả JSON khi thành công, và ném ba loại ngoại lệ khác nhau để phía gọi xử lý đúng: dừng hẳn, bỏ qua dòng, hay để lượt sau.

Một chi tiết về hết giờ phía bạn

Nếu kết nối đứt hoặc hết 120 giây phía bạn, bạn không biết lượt đó đã được xử lý tới đâu. Điểm được trừ khi máy chủ nhận yêu cầu, và hình ảnh không vẽ được thì hoàn điểm. Nhưng nếu đứt mạng đúng lúc hình ảnh đã vẽ xong và đang trả về, lượt đó có thể đã được tính. Đây là lý do không nên đặt thời gian chờ quá ngắn (dưới 100 giây), và nên ghi lại thời điểm những lượt đứt mạng để đối chiếu với lịch sử điểm nếu thấy chênh.

Hàng đợi: đừng giữ việc trong bộ nhớ

Vòng for trên danh sách hai trăm dòng có một điểm yếu: tắt máy, mất điện, hay một lỗi lạ ở dòng 137 là phải chạy lại từ đầu, hoặc tệ hơn, chạy lại cả những dòng đã trừ điểm. Hàng đợi bằng một tệp SQLite giải quyết chuyện này với chưa tới năm mươi dòng mã.

```python
import base64
import json
import sqlite3
import time
from pathlib import Path

DB = sqlite3.connect("hang_doi.sqlite")
DB.execute("""CREATE TABLE IF NOT EXISTS viec(
id INTEGER PRIMARY KEY,
ten TEXT UNIQUE,
payload TEXT NOT NULL,
trang_thai TEXT NOT NULL DEFAULT 'cho',
so_lan INTEGER NOT NULL DEFAULT 0,
lan_sau REAL NOT NULL DEFAULT 0,
loi TEXT,
diem INTEGER NOT NULL DEFAULT 0)""")
DB.commit()
THU_MUC = Path("ra")
THU_MUC.mkdir(exist_ok=True)

def them(ten: str, payload: dict) -> None:
DB.execute("INSERT OR IGNORE INTO viec(ten, payload) VALUES (?, ?)",
(ten, json.dumps(payload, ensure_ascii=False)))
DB.commit()

def chay() -> None:
while True:
row = DB.execute(
"SELECT id, ten, payload, so_lan FROM viec "
"WHERE trang_thai IN ('cho', 'tam') AND lan_sau <= ? "
"ORDER BY id LIMIT 1", (time.time(),)).fetchone()
if not row:
con = DB.execute("SELECT COUNT(*) FROM viec WHERE trang_thai='tam'").fetchone()[0]
if con == 0:
print("Xong hàng đợi.")
return
time.sleep(30)
continue
vid, ten, payload, so_lan = row
try:
kq = ve(json.loads(payload))
except LoiDungHan as e:
print("DỪNG:", e)
return
except LoiDuLieu as e:
DB.execute("UPDATE viec SET trang_thai='hong', loi=? WHERE id=?", (str(e), vid))
except LoiTamThoi as e:
moi = 'tam' if so_lan + 1 < 3 else 'hong' # quá 3 lượt thì để người xem
DB.execute("UPDATE viec SET trang_thai=?, so_lan=so_lan+1, loi=?, "
"lan_sau=? WHERE id=?", (moi, str(e), time.time() + 600, vid))
else:
for i, d in enumerate(kq["data"], 1):
(THU_MUC / f"{ten}-{i}.webp").write_bytes(base64.b64decode(d["b64_json"]))
DB.execute("UPDATE viec SET trang_thai='xong', diem=? WHERE id=?",
(kq["usage"]["credits"], vid))
DB.commit()
```

Dùng:

```python
them("bia-bai-pho-ha-noi", {"model": "plus", "size": "1536x1024", "n": 1,
"output_format": "webp",
"prompt": "A steaming bowl of pho on a street stall table in Hanoi, morning light, realistic photo"})
chay()
```

Những gì hàng đợi này cho bạn:

  • Không chạy lại dòng đã xong. Cột ten là duy nhất; thêm lại cùng tên bị bỏ qua, dòng xong không bao giờ được chọn lại.
  • Dòng lỗi tạm thời được để lượt sau, mười phút sau mới thử lại, trong khi các dòng khác vẫn chạy; quá ba lượt vẫn bận thì chuyển sang hong để người xem.
  • Dòng lỗi dữ liệu đứng yên với trạng thái hong và lý do trong cột loi, chờ người sửa.
  • Dừng sạch khi hết điểm hay sai khoá, chạy lại sau khi xử lý thì tiếp tục đúng chỗ.
  • Cột diem cộng lại là tổng chi phí thật của cả đợt.

Một tiến trình hay nhiều tiến trình

Bản năng của lập trình viên là chạy song song cho nhanh. Với API này, chạy song song nhiều hơn hai luồng thường chậm hơn tổng thể: các luồng tranh nhau chỗ, nhận 503, ngủ, rồi lại tranh. Mỗi tài khoản trên trang web cũng chỉ vẽ một lượt một lúc, và API đi chung máy vẽ đó.

Cách chạyƯuNhược
Một tiến trình tuần tựĐơn giản, ít 503, dễ đoán thời gianKhông tận dụng lúc máy rảnh
Hai tiến trìnhNhanh hơn chút khi máy rảnhPhải khoá dòng khi chọn việc
Nhiều hơn haiKhông nhanh hơn503 dày, khó theo dõi

Nếu chạy hai tiến trình với hàng đợi trên, cần đánh dấu dòng là dang trong cùng một giao dịch trước khi gọi ve(), để hai tiến trình không chọn cùng một dòng.

Ước lượng thời gian một đợt

Một cửa hàng gốm sứ Bát Tràng cần 180 hình ảnh hạng Plus khổ vuông cho gian hàng mới. Mỗi hình ảnh Plus mất khoảng 6–10 giây; gửi n: 2 mỗi lượt thì mỗi lượt khoảng 15–20 giây cộng thời gian truyền. 90 lượt tuần tự là khoảng 25–35 phút nếu máy rảnh, và có thể lâu gấp đôi vào giờ bận. Hãy cho đợt chạy bắt đầu từ tối hôm trước, đừng chờ sáng hôm cần đăng.

Chi phí thì tính trước được chính xác: 180 × 500 = 90.000 điểm. Cách đặt trần chi phí cho cả đợt có ở bài tạo hàng loạt hình ảnh sản phẩm từ CSV.

Tóm lại

  • 503 là đèn đỏ: chờ đúng Retry-After, cộng độ lệch ngẫu nhiên, giới hạn số lần.
  • 400 là lỗi của dòng; 401, 402 là lỗi của tài khoản, phải dừng cả hàng đợi.
  • 200 có thể ít hình ảnh hơn n, phần thiếu đã được hoàn điểm.
  • Giữ việc trong hàng đợi SQLite, chạy một hoặc hai tiến trình.

Tạo khoá ở trang khoá API; nếu đang chuyển từ OpenAI, xem trước bài chuyển mã OpenAI Images sang AI Hình Ảnh.

Hỏi đáp nhanh

Retry-After thường là bao nhiêu giây?
Thường vài chục giây, tuỳ lúc. Đọc đúng giá trị trong header mỗi lần thay vì đặt cứng một con số, rồi cộng thêm vài giây ngẫu nhiên nếu bạn chạy nhiều tiến trình.
Bị 503 có bị trừ điểm không?
Không có hình ảnh nào được vẽ thì không mất điểm. Nếu lượt đã nhận mà hình ảnh không vẽ được, phần điểm đó tự hoàn về ví.
Thư viện openai có tự thử lại không?
Có, thư viện chính thức cho Python và Node.js tự thử lại một vài lần với lỗi 5xx và đọc Retry-After. Với chạy hàng loạt, tự viết vòng thử lại như trong bài giúp kiểm soát số lần và tách rõ lỗi cần dừng.
Chạy mười luồng song song có nhanh hơn không?
Thường là không. Máy vẽ nhận số lượt đồng thời có hạn, các luồng thừa chỉ nhận 503 rồi ngủ. Một hoặc hai tiến trình tuần tự cho tổng thời gian tốt nhất.
Đứt mạng giữa chừng thì lượt đó có bị tính không?
Có thể, nếu hình ảnh đã vẽ xong đúng lúc kết nối đứt. Đặt thời gian chờ phía bạn từ 100 giây trở lên và ghi lại các lượt đứt mạng để đối chiếu với lịch sử điểm.
Tạo hình ảnh bằng AI từ mô tả tiếng ViệtGõ mô tả tiếng Việt, chọn hạng Plus, Pro hoặc Max — có hình ảnh trong vài giây.
Vẽ hình ảnh ngay

Đọc tiếp

Liên hệ AI Hình Ảnh
📞 Gọi 0918 832 283💬 Chat Zalo🟢 WhatsAppĐóng