Hướng dẫn AgentFlow

Thử lại an toàn

Gửi lại một yêu cầu tạo hay khởi chạy với cùng Idempotency-Key mà không làm việc hai lần — thao tác nào nhận khóa, thế nào là cùng một yêu cầu, lần phát lại trả về gì, và nên làm gì với bốn mã lỗi.

Vì sao cần

Một yêu cầu có thể hết thời gian chờ, hoặc mất kết nối, sau khi server đã làm xong việc. Gửi lại mù quáng thì bạn có hai hồ sơ, hay hai lượt chạy. Hãy gửi kèm header Idempotency-Key: gửi lại với cùng khóa sẽ nhận về kết quả gốc, và không có gì được làm lần hai.

Gửi một khóa

export IDEMPOTENCY_KEY=$(uuidgen)

curl -sS -X POST "$ORIGIN/api/v1/workflows/$WORKFLOW_ID/instances" \
  -H "Authorization: Bearer $AGENTFLOW_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $IDEMPOTENCY_KEY" \
  -d '{"name": "Đề xuất mua 10 laptop", "input_payload": {"so_luong": 10}}'
  • Khóa gồm 1–255 ký tự ASCII in được. Nên dùng một UUID: sinh một lần cho mỗi việc bạn muốn làm, rồi dùng lại đúng khóa đó ở mọi lần gửi lại.
  • Khóa thuộc về một danh tính trong một tổ chức — một chủ thể dịch vụ, hoặc một người. Hai danh tính tình cờ gửi cùng một khóa là hai yêu cầu không liên quan gì nhau.
  • Khóa có hiệu lực 24 giờ theo mặc định; bản triển khai có thể đặt khác. Hết thời hạn, cùng khóa được coi là một yêu cầu mới.

Thao tác nào nhận khóa

Thao tácPhương thức và đường dẫn
Tạo hồ sơPOST /entities/{entity_id}/records
Sửa một vài trường của hồ sơPATCH /entities/{entity_id}/records/{record_id}
Khởi chạy một lượt chạyPOST /workflows/{workflow_id}/instances
Khởi chạy lượt chạy hàng loạtPOST /entities/{entity_id}/records/batch-runs
Tải tệp lênPOST /attachments
Gửi bước của một công việcPOST /entities/{entity_id}/records/{record_id}/step/submit
  • Trong tài liệu tham chiếu, các thao tác này mang x-idempotent: true. Hãy dựa vào dấu hiệu đó thay vì chép lại bảng này.
  • Gửi một bước là x-person-only: chủ thể dịch vụ gọi sẽ nhận 403 USER_IDENTITY_REQUIRED.
  • Các thao tác công việc (nhận, trả lại, giao lại, giao việc) không nhận khóa. Một công việc được nhận và trả lại như mọi bản ghi công việc, và gửi lại một lượt nhận bạn đã thắng sẽ trả 409 WORK_ALREADY_CLAIMED: sau mỗi lần quá thời gian chờ, hãy đọc lại bản ghi trước.
  • Khóa gửi tới một thao tác khác bị bỏ qua, như mọi header mà thao tác đó không đọc. Một lớp thử lại dùng chung, gắn khóa vào mọi POST, vẫn hoạt động bình thường.

Thế nào là cùng một yêu cầu

Server so dấu vân tay (fingerprint) của yêu cầu gửi lại với dấu vân tay của yêu cầu gốc. Dấu vân tay gồm:

  • phương thức, đường dẫn và giá trị các tham số đường dẫn;
  • chuỗi truy vấn — tên các tham số theo thứ tự nào cũng được, nhưng các giá trị lặp của cùng một tham số giữ nguyên thứ tự: ?a=1&a=2 khác ?a=2&a=1;
  • thân yêu cầu — với JSON, thứ tự khóa và khoảng trắng không quan trọng; thứ tự phần tử trong mảng và cách viết số thì có: 1 khác 1.0;
  • với tải tệp lên, nội dung tệp, tên tệp và kiểu nội dung, thay cho thân yêu cầu.

Cùng khóa với một yêu cầu khác bị từ chối 422 IDEMPOTENCY_KEY_MISMATCH, và yêu cầu đó không được thực hiện. Muốn làm một việc khác, hãy dùng khóa mới.

Lần phát lại trả về gì

Khi cùng khóa và cùng yêu cầu tới trong thời hạn, sau khi yêu cầu gốc đã thành công:

HTTP/1.1 201 Created
Content-Type: application/json
Idempotent-Replayed: true

{ "id": "c04b…", "status": "running", … }
  • Trạng thái gốc — ở đây 201.
  • Tài nguyên như hiện tại, không phải bản sao của phản hồi cũ: nếu hồ sơ đã được sửa kể từ đó, bạn thấy bản đã sửa.
  • Idempotent-Replayed: true. Phản hồi của yêu cầu gốc không có header này.
  • Không có gì được tạo, khởi chạy hay thay đổi lần hai.

Lần phát lại trả về kết quả gốc, không đánh giá lại hành động:

  • Quyền thực hiện không bị kiểm tra lại. Một vai trò bị gỡ sau yêu cầu gốc không biến lần phát lại thành 403. Nhưng tài nguyên vẫn được đọc lại theo quyền đọc hiện tại của bạn.
  • Khởi chạy có chờ (wait_ms, xem ví dụ): lần phát lại trả 202 khi lượt chạy còn đang chạy, 200 khi không, và không chờ lại.
  • Sửa hồ sơ: expected_updated_at không bị kiểm tra lại, nên lần phát lại không trả 409 STALE_VERSION dù hồ sơ đã đổi.
  • Gửi một bước: trả 200 với bảng của bước như bạn đọc được lúc này, và gọi công việc bằng mã bản ghi của nó. Một lượt gửi bị từ chối — biểu mẫu không hợp lệ, hoặc việc ghi vào bản ghi mà công việc nói tới bị từ chối — không làm mất khóa, nên sau khi bạn sửa nguyên nhân, cùng khóa đó sẽ thực hiện lượt gửi đúng một lần.

Tài nguyên không còn

Nếu tài nguyên đã bị xóa, hoặc bạn không còn được thấy nó, lần phát lại trả 410 IDEMPOTENT_RESOURCE_GONE. extensions.idempotency nêu loại và id của tài nguyên:

{
  "type": "IDEMPOTENT_RESOURCE_GONE",
  "title": "Gone",
  "status": 410,
  "detail": "…",
  "request_id": "…",
  "instance": "/api/v1/entities/…/records",
  "extensions": { "idempotency": { "resource_kind": "record", "resource_id": "7d2e…" } }
}
  • resource_kind hiện là một trong record, instance, batch_run, attachment, task. Danh sách này có thể được bổ sung về sau.
  • Với một lượt gửi, resource_kind là task và resource_id là mã bản ghi Workflow task của công việc; 410 xảy ra khi bản ghi của công việc không còn tồn tại hoặc bạn không còn mở được bước của nó.

Chỉ kết quả thành công được ghi nhận

Khóa chỉ được ghi nhận khi yêu cầu thành công. Một yêu cầu bị từ chối — ví dụ 422 vì dữ liệu không hợp lệ — không để lại gì: sửa yêu cầu rồi gửi lại với cùng khóa.

Hai yêu cầu cùng lúc

Khi yêu cầu gốc vẫn đang chạy, một lần gửi lại với cùng khóa nhận 409 IDEMPOTENCY_KEY_IN_PROGRESS kèm Retry-After: 1. Chờ chừng ấy giây rồi gửi lại với cùng khóa: nếu yêu cầu gốc đã thành công, bạn nhận lần phát lại; nếu nó thất bại, lần gửi của bạn được xử lý như một yêu cầu mới.

Hết thời gian chờ có thể che một thành công

Một yêu cầu có thể hết thời gian chờ, hoặc mất kết nối, sau khi việc đã được ghi. Đừng coi đó là thất bại. Gửi lại với cùng khóa là cách biết kết quả thật:

  • Phản hồi có Idempotent-Replayed: true: việc đã được làm từ trước, và đây là kết quả của nó.
  • Phản hồi thành công không có header đó: yêu cầu trước không thành công hoặc chưa tới server, và bây giờ việc đã được làm đúng một lần.

Bốn mã lỗi

Trạng tháiMã (type)Khi nàoNên làm gì
400IDEMPOTENCY_KEY_INVALIDKhóa rỗng, dài hơn 255 ký tự, có ký tự ngoài ASCII in được, hoặc header được gửi hai lần. field_errors có một mục với path là Idempotency-Key.Sửa khóa. Gửi lại y nguyên không giúp gì.
409IDEMPOTENCY_KEY_IN_PROGRESSYêu cầu gốc với khóa này vẫn đang chạy.Đáng thử lại: chờ theo Retry-After (1 giây), rồi gửi lại với cùng khóa.
422IDEMPOTENCY_KEY_MISMATCHKhóa đã được dùng cho một yêu cầu khác.Dùng khóa mới cho yêu cầu mới. Gửi lại y nguyên không giúp gì.
410IDEMPOTENT_RESOURCE_GONETài nguyên mà khóa đã tạo bị xóa, hoặc bạn không còn thấy nó.Đừng thử lại: kết quả sẽ y như vậy.

Toàn bộ danh mục nằm ở Mã lỗi; cách đọc một lỗi nằm ở Lỗi.

Gọi từ trình duyệt

Một ứng dụng chạy trong trình duyệt, trên một nguồn gốc (origin) mà bản triển khai cho phép, gửi được header Idempotency-Key và đọc được header Idempotent-Replayed của phản hồi.

On this page