Conceptos clave
Idempotencia y seguridad ante reintentos
Cómo hace Maple que los reintentos sean seguros sin una clave de idempotencia: decisiones seguras ante reintentos, menús aplicados como diferencias, repetición idempotente y deduplicación de su lado.
Las redes fallan a mitad de una solicitud. La pregunta que importa es: si reintenta, ¿algo ocurrirá dos veces? Con Maple, las escrituras que más reintentará están diseñadas para poder repetirse sin riesgo, así que puede reintentar tras un tiempo de espera agotado sin conciliar primero.
Las decisiones sobre pedidos son seguras ante reintentos
Repetir una decisión sobre un pedido (accept, deny, ready, complete, cancel o status) devuelve el mismo acuse de recibo sin aplicar el efecto secundario dos veces:
{ "object": "order_decision", "order_id": "ord_...", "decision": "accept", "status": "received" }Si envía accept y la respuesta agota el tiempo de espera, envíelo de nuevo. El pedido se acepta exactamente una vez y usted recibe { "status": "received" } en ambos casos. Así, un ciclo simple de reintento ante errores transitorios es correcto sin que usted tenga que llevar ningún registro adicional.
Publicar un menú es aplicar una diferencia
Una publicación de menú describe el estado deseado de todo el menú y se aplica como una diferencia respecto de lo que está publicado actualmente, usando como clave sus externalId:
- Volver a publicar un documento idéntico no hace nada.
- Las identidades de los objetos se mantienen estables entre publicaciones según el
externalId, así que republicar no recrea ni altera objetos. - La validación es de todo o nada: un
400no cambia nada, por lo que una publicación fallida deja el menú exactamente como estaba.
Por lo tanto, si una publicación agota el tiempo de espera, reenviar el mismo documento es seguro. Vea Publicar un menú.
Las escrituras de reservas llevan un idempotency_key
Crear, modificar o cancelar una reserva (POST /v1/bookings, POST /v1/bookings/{id}/change, POST /v1/bookings/{id}/cancel), cancelarla como el establecimiento (POST /v1/bookings/{id}/venue_cancel) y sentar a un cliente sin reserva (POST /v1/locations/{locationId}/walk_ins) requieren un idempotency_key en el cuerpo, limitado a su app. Las claves de clientes sin reserva, al igual que las de las incorporaciones a la lista de espera, pertenecen a su app en todos sus locales. Las claves deben tener de 1 a 255 caracteres. Para las reservas nativas de Maple, el registro guarda la escritura y el resultado de su repetición en una sola transacción:
- Reintentar con la misma clave y la misma solicitud repite el resultado original: usted recibe la misma
bookingy nada se reserva, se mueve ni se cancela dos veces. - La misma clave con una solicitud distinta (otro cliente, otro horario u otra nota) responde
409concode: "idempotency_key_reused". Genere una clave nueva por cada escritura que desee hacer; un UUID sirve.
Un reintento devuelve la misma identidad de reserva sin volver a aplicar la modificación; la respuesta se lee de la reserva actual. Las claves tienen una ventana de repetición de 24 horas desde el primer uso. Las repeticiones se verifican antes que expected_version, que con frecuencia estará desactualizada después de que la escritura original tuvo éxito.
Las retenciones nativas y de proveedores se conservan y pertenecen a la app que las obtuvo. Repetir el mismo slot_token reproduce la retención activa de la app sin tomar otro bloqueo. Otra app no puede consumirla ni liberarla, incluso en un local con acceso otorgado a ambas. Las retenciones de proveedor desconocidas liberan su reserva de cuota después de una cuarentena conservadora de 24 horas de inactividad, independientemente de su registro de auditoría conservado; las operaciones vencidas no pueden revivirse reintentando.
Escrituras respaldadas por un proveedor
Para OpenTable, Maple registra de forma duradera la clave y el resumen de la solicitud antes de cualquier E/S con el proveedor y usa un único ID de solicitud estable ante el proveedor. Un cambio o una cancelación pendiente también reserva la reserva reflejada frente a otras escrituras de socios. Cuando tiene éxito, Maple registra el reflejo y el resultado de la repetición juntos. Las fallas transitorias del reflejo se reintentan de forma sincrónica; un conciliador en segundo plano repara el trabajo pendiente.
Un tiempo de espera agotado del proveedor devuelve 409 operation_in_progress mientras el resultado no esté resuelto. Reintente la misma solicitud con la misma clave después de details.retry_after segundos. Maple realiza una lectura de conciliación antes de repetir una escritura de reserva con el ID de solicitud original del proveedor. Las escrituras completadas se repiten sin volver a llamar al proveedor.
La configuración de reservas usa en cambio una publicación direccionada por contenido: una configuración idéntica no hace nada, sin necesidad de una clave explícita. Los verbos de estado del establecimiento (confirmar, rechazar, sentar, completar, no se presentó) reciben expected_version, no una clave de idempotencia; después de una respuesta ambigua, lea la reserva antes de tomar otra acción. La cancelación por parte del establecimiento y los clientes sin reserva sí reciben un idempotency_key, limitado a su app como todas las demás claves.
{ "hold_id": "bkh_…", "guest": { "first_name": "Alex", "last_name": "Quinn", "phone": "+12125551234" }, "idempotency_key": "6f1c…" }Repetir un evento es idempotente
POST /v1/webhook_events/{eventId}/replay vuelve a entregar un evento solo a las suscripciones que aún no lo han recibido. Las suscripciones que ya lo recibieron se omiten, así que repetir un evento después de una caída no genera entregas dobles a los endpoints que funcionan bien.
De su lado: deduplique las entregas
El único lugar donde usted debe agregar idempotencia es su manejador de webhooks. La entrega es de al menos una vez, así que el mismo evento puede llegar más de una vez. Deduplique usando el id del sobre:
async function handleEvent(event: { id: string; type: string; data: unknown }) { if (await alreadyProcessed(event.id)) return; // no-op on a repeat await process(event); await markProcessed(event.id);}Haga que el trabajo en sí sea idempotente cuando pueda; por ejemplo, use el order_id de Maple como clave de sus propios registros de pedidos, de modo que un order.notification duplicado actualice en lugar de duplicar. No dependa del orden de los eventos; concilie con GET /v1/orders/{orderId} cuando la secuencia importe. Vea Webhooks.
Resumen
| Operación | ¿Es seguro reintentar? | Por qué |
|---|---|---|
| Decisiones sobre pedidos | Sí | Seguras ante reintentos; las repeticiones devuelven received sin efecto doble |
| Publicación de menú | Sí | Se aplica como diferencia; volver a publicar lo idéntico no hace nada |
| Repetición de eventos | Sí | Omite las suscripciones que ya recibieron la entrega |
| Crear / modificar / cancelar reserva nativa | Sí, con su idempotency_key |
Misma clave + mismo cuerpo se repite; misma clave + cuerpo distinto es 409 idempotency_key_reused |
| Clientes sin reserva y cancelación por el establecimiento | Sí, con su idempotency_key |
Misma clave + mismo cuerpo repite la misma reserva, incluso después de que se ocupe su mesa; misma clave + cuerpo distinto (o, en el caso de clientes sin reserva, otro local) es 409 idempotency_key_reused |
| Retenciones de reservas nativas | Mientras la retención original esté activa | Volver a presentar su slot_token devuelve la retención activa |
| Escrituras y retenciones de reservas con proveedor | Con la misma clave / cotización | Registros duraderos e IDs de solicitud estables ante el proveedor; los resultados sin resolver pueden requerir conciliación |
| Configuración de reservas | Sí | Una configuración idéntica no hace nada (direccionada por contenido) |
| Recepción de webhooks | Usted deduplica | Entrega de al menos una vez: deduplique por el id del evento |