Skip to content

SDK de Java: API bloqueante (SRE, DLS, webhooks y mocks) - #1

Merged
thomyluca merged 9 commits into
mainfrom
sdk-bloqueante
Oct 3, 2026
Merged

thomyluca merged 9 commits into
mainfrom
sdk-bloqueante

Conversation

@thomyluca

Copy link
Copy Markdown
Contributor

Primera etapa del SDK de Java: la API bloqueante completa, espejo de @caerus-dev/sdk 0.5.0.

Qué trae

  • SRE (CaerusClient), DLS (DlsClient, con withTransaction, renovación automática, cola, onQueued y cancelación) y webhooks.
  • Clientes en memoria (InMemoryCaerusClient, InMemoryDlsClient) que implementan las mismas interfaces y son thread-safe.
  • Java 17, Maven, io.github.caerus-dev:caerus-sdk, paquete dev.caerus.sdk.
  • El cliente gRPC se genera en el build desde una copia del .proto de caerus-back (commit y SHA-256 en proto/README.md), con el paquete Java movido a dev.caerus.sdk.internal.proto para que no choque con las clases del motor.

Cómo se verificó

  • mvn verify: 366 tests contra un servidor gRPC real en 127.0.0.1. Son los de TypeScript portados más tests de concurrencia con hilos.
  • Dos tests cuidan las reglas: nada de protobuf, gRPC, Gson ni del paquete internal aparece en una firma pública (se probó metiendo una filtración a propósito), y el código no lleva comentarios.
  • La firma de webhooks da byte a byte lo mismo que el motor y que el SDK de TypeScript.
  • Contra el motor hospedado (mvn test -Plive), en verde:
    • SRE completo con la plantilla butaca: crear, tomar con idempotencia, extender, quedarse sin stock, confirmar, borrar con holders, buscar por grupo, actualizar stock.
    • DLS: lectura compartida, deadlock de dos (la víctima siempre es la más joven, 3 de 3 corridas) y de tres, cola con onQueued, deadline del cliente, transacción cerrada, renovación, fencing tokens crecientes.
    • Errores de API Key inválida y requestId en los errores.
  • Faltan los escenarios de las plantillas de locks FAIL y ALERT, que todavía no existen en el entorno.

Diferencias con el SDK de TypeScript

Están en docs/paridad.md: qué cambia por ser Java y qué se decidió con cada inconsistencia del SDK de TS. La única que cambia comportamiento es que InMemoryDlsClient.releaseLock de un lock inexistente no lanza error, igual que el motor. Se va a proponer el mismo cambio para TS.

Lo que viene

La API asíncrona (CompletableFuture) sobre el mismo núcleo, antes de 1.0, y la publicación en Maven Central.

El .proto se copia byte a byte de caerus-back, que es privado, y su README
registra commit y SHA-256 para poder comparar. El build lo copia a target,
cambia el java_package a dev.caerus.sdk.internal.proto y genera desde ahi:
las clases generadas quedan marcadas como internas y no chocan con las del
motor si alguien tiene las dos en el classpath.

Java 17 como minimo, protobuf 3.25 para no forzarle a nadie la 4.x (es la que
pide grpc-java), y la version del jar inyectada desde el pom.
CaerusError es unchecked para que un solo catch alcance, con code, reason y
requestId como en TypeScript. El reason se lee del ErrorInfo del trailer y
nunca lanza: un trailer roto deja el error como estaba en vez de taparlo con
otro.

Cada llamada lleva su API Key, un x-request-id propio y un deadline. No hay
reintentos. Un solo nucleo asincrono sobre grpc-java, para que la API
asincrona de la etapa 2 sea una fachada y no una segunda implementacion.

Dos tests cuidan las reglas: nada de protobuf, gRPC, Gson ni del paquete
internal aparece en una firma publica, y el codigo no lleva comentarios.
Mismos metodos que en TypeScript, con builders en lugar de objetos de
opciones y una sobrecarga sin opciones para cada uno. Valida antes de llamar
y nombra el argumento; un take o un extend que vuelven en un estado que no
sirven lanzan ConflictError, y un estado desconocido lanza en vez de
adivinar. La metadata viaja como JSON y vuelve como Map; los tiempos en cero
vuelven vacios, nunca como 1970.

InMemoryCaerusClient copia al de TypeScript y ademas es thread-safe, porque
en Java los tests usan hilos de verdad.

Los tests de TypeScript portados corren contra un servidor gRPC real en
127.0.0.1, no contra un stub.
acquireLock consume el stream: avisa onQueued una sola vez y nunca despues de
conceder, corta con un AbortSignal y convierte un DENIED en LockDeniedError.
Sin timeout propio usa el deadline del cliente, como en TypeScript.

withTransaction renueva desde un ScheduledExecutorService del cliente (Java
17 no tiene virtual threads) que se apaga en close(), suelta los locks en
el finally y lanza la perdida de la transaccion aunque el callback haya
terminado bien. Una excepcion checked del callback sale tal cual.

El cliente en memoria responde OK al soltar un lock que no existe, como el
motor, en lugar de lanzar DlsNotFoundError como el de TypeScript.
HMAC-SHA256 sobre el cuerpo crudo, comparado en tiempo constante y con cinco
minutos de tolerancia. El vector cruzado de TypeScript y del motor da la
misma firma byte a byte. Cada evento tiene su record y un tipo que el SDK no
conoce llega como UnknownEventData, para que un evento nuevo del motor no
rompa a nadie.
Los tests de TypeScript contra el mock pasaban las dos veces que el SDK tuvo
un bug de contrato, asi que esto no es opcional. Corre con mvn test -Plive y
CAERUS_API_KEY; queda fuera de mvn verify. Contra el motor hospedado pasaron
los escenarios de lectura compartida, deadlock de dos y de tres, cola con
onQueued, deadline del cliente, transaccion cerrada, renovacion, fencing
tokens, API Key invalida y requestId. Faltan las plantillas FAIL, ALERT y
una de recursos para el resto.
paridad.md deja escrito que cambia por ser Java y que se decidio con cada
inconsistencia del SDK de TypeScript, para que la proxima version no las
redescubra.
El escenario contaba cuantas transacciones abortaba el motor por deadlock y
daba bien con cero, pero tambien daba cero cuando la plantilla no existia y
las dos fallaban por NOT_FOUND. Ahora la unica falla aceptada es el timeout.

El SRE en vivo paso entero contra la plantilla butaca, salvo updateResource,
que esa plantilla exige con clave de idempotencia: el test ahora la manda.
Copilot AI balanced review requested due to automatic review settings October 3, 2026 15:52

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Transaction renewal races, cancellation gaps, webhook byte handling, and in-memory DLS parity defects can produce incorrect runtime behavior.

Review effort: Balanced
Findings: 5 Medium severity · 1 Low severity

Open (6)
What changed in this PR

Introduces the first blocking Java SDK for Caerus, covering SRE, DLS, webhooks, in-memory clients, generated gRPC contracts, documentation, and verification.

Changes:

  • Adds blocking SRE and DLS APIs with typed models and errors.
  • Adds webhook verification and typed event decoding.
  • Adds mocks, contract tests, live tests, Maven build, and CI.
File Description
.gitattributes Preserves proto checksums.
.gitignore Excludes local artifacts.
.github/​workflows/​tests.yml Runs Maven verification.
LICENSE Adds MIT license.
README.md Documents SDK usage.
pom.xml Configures Java, gRPC, and tests.
proto/​README.md Documents proto provenance.
proto/​dls_service.proto Defines DLS contract.
proto/​sre_service.proto Defines SRE contract.
docs/​errores.md Documents error handling.
docs/​paridad.md Records TypeScript parity.
docs/​verificacion-en-vivo.md Documents live verification.
src/​main/​resources/​dev/​caerus/​sdk/​version.properties Exposes build version.
src/​main/​java/​dev/​caerus/​sdk/​AbortController.java Controls cancellation.
src/​main/​java/​dev/​caerus/​sdk/​AbortSignal.java Publishes cancellation state.
src/​main/​java/​dev/​caerus/​sdk/​CaerusError.java Defines base SDK error.
src/​main/​java/​dev/​caerus/​sdk/​CaerusErrorOptions.java Configures error details.
src/​main/​java/​dev/​caerus/​sdk/​CaerusLogger.java Defines logging callback.
src/​main/​java/​dev/​caerus/​sdk/​CaerusSdk.java Exposes SDK constants.
src/​main/​java/​dev/​caerus/​sdk/​ErrorCode.java Defines error categories.
src/​main/​java/​dev/​caerus/​sdk/​ErrorReason.java Defines engine reasons.
src/​main/​java/​dev/​caerus/​sdk/​internal/​ClientProfile.java Defines client profiles.
src/​main/​java/​dev/​caerus/​sdk/​internal/​ClientSettings.java Resolves client configuration.
src/​main/​java/​dev/​caerus/​sdk/​internal/​ErrorDetails.java Decodes gRPC errors.
src/​main/​java/​dev/​caerus/​sdk/​internal/​Futures.java Bridges asynchronous operations.
src/​main/​java/​dev/​caerus/​sdk/​internal/​GrpcTransport.java Implements gRPC transport.
src/​main/​java/​dev/​caerus/​sdk/​internal/​Json.java Provides JSON utilities.
src/​main/​java/​dev/​caerus/​sdk/​internal/​StderrLogger.java Implements default logging.
src/​main/​java/​dev/​caerus/​sdk/​sre/​AuthenticationError.java Adds SRE authentication error.
src/​main/​java/​dev/​caerus/​sdk/​sre/​CaerusClient.java Implements blocking SRE client.
src/​main/​java/​dev/​caerus/​sdk/​sre/​CaerusClientOptions.java Configures SRE clients.
src/​main/​java/​dev/​caerus/​sdk/​sre/​ConfirmOptions.java Configures confirmations.
src/​main/​java/​dev/​caerus/​sdk/​sre/​ConflictError.java Adds SRE conflict error.
src/​main/​java/​dev/​caerus/​sdk/​sre/​CreateResourceOptions.java Configures resource creation.
src/​main/​java/​dev/​caerus/​sdk/​sre/​GetResourcesByGroupOptions.java Configures group pagination.
src/​main/​java/​dev/​caerus/​sdk/​sre/​Handles.java Builds resource handles.
src/​main/​java/​dev/​caerus/​sdk/​sre/​HolderNotActiveError.java Adds inactive-holder error.
src/​main/​java/​dev/​caerus/​sdk/​sre/​HolderSort.java Defines holder ordering.
src/​main/​java/​dev/​caerus/​sdk/​sre/​InMemoryCaerusClient.java Implements in-memory SRE.
src/​main/​java/​dev/​caerus/​sdk/​sre/​ListResourceHoldersOptions.java Configures holder queries.
src/​main/​java/​dev/​caerus/​sdk/​sre/​MockMethod.java Identifies mocked methods.
src/​main/​java/​dev/​caerus/​sdk/​sre/​MockOptions.java Configures SRE mocks.
src/​main/​java/​dev/​caerus/​sdk/​sre/​MockResourceSeed.java Defines mock resources.
src/​main/​java/​dev/​caerus/​sdk/​sre/​MockSnapshot.java Captures mock state.
src/​main/​java/​dev/​caerus/​sdk/​sre/​OutOfStockError.java Adds stock error.
src/​main/​java/​dev/​caerus/​sdk/​sre/​PooledResource.java Defines pooled operations.
src/​main/​java/​dev/​caerus/​sdk/​sre/​Resource.java Models resources.
src/​main/​java/​dev/​caerus/​sdk/​sre/​ResourceHasActiveHoldsError.java Adds active-holds error.
src/​main/​java/​dev/​caerus/​sdk/​sre/​ResourceHasQueuedRequestsError.java Adds queued-requests error.
src/​main/​java/​dev/​caerus/​sdk/​sre/​ResourceHolder.java Models resource holders.
src/​main/​java/​dev/​caerus/​sdk/​sre/​ResourceHolderPage.java Models holder pages.
src/​main/​java/​dev/​caerus/​sdk/​sre/​ResourceHolderStatus.java Defines holder states.
src/​main/​java/​dev/​caerus/​sdk/​sre/​ResourceNotFoundError.java Adds resource error.
src/​main/​java/​dev/​caerus/​sdk/​sre/​ResourcePage.java Models resource pages.
src/​main/​java/​dev/​caerus/​sdk/​sre/​SharedResourceApi.java Defines blocking SRE API.
src/​main/​java/​dev/​caerus/​sdk/​sre/​SreCore.java Implements SRE requests.
src/​main/​java/​dev/​caerus/​sdk/​sre/​SreErrors.java Maps SRE errors.
src/​main/​java/​dev/​caerus/​sdk/​sre/​SreMapping.java Maps SRE models.
src/​main/​java/​dev/​caerus/​sdk/​sre/​TakeOptions.java Configures reservations.
src/​main/​java/​dev/​caerus/​sdk/​sre/​TimeoutError.java Adds SRE timeout error.
src/​main/​java/​dev/​caerus/​sdk/​sre/​UnitaryResource.java Defines unitary operations.
src/​main/​java/​dev/​caerus/​sdk/​sre/​UpdateResourceOptions.java Configures resource updates.
src/​main/​java/​dev/​caerus/​sdk/​sre/​Validation.java Validates SRE inputs.
src/​main/​java/​dev/​caerus/​sdk/​sre/​ValidationError.java Adds validation error.
src/​main/​java/​dev/​caerus/​sdk/​dls/​AcquireLockOptions.java Configures lock acquisition.
src/​main/​java/​dev/​caerus/​sdk/​dls/​ActiveLockHolder.java Models active holders.
src/​main/​java/​dev/​caerus/​sdk/​dls/​BeginTransactionOptions.java Configures transactions.
src/​main/​java/​dev/​caerus/​sdk/​dls/​DeadlockAbortedError.java Adds deadlock error.
src/​main/​java/​dev/​caerus/​sdk/​dls/​DlsApi.java Defines blocking DLS API.
src/​main/​java/​dev/​caerus/​sdk/​dls/​DlsAuthenticationError.java Adds DLS authentication error.
src/​main/​java/​dev/​caerus/​sdk/​dls/​DlsClient.java Implements blocking DLS client.
src/​main/​java/​dev/​caerus/​sdk/​dls/​DlsClientOptions.java Configures DLS clients.
src/​main/​java/​dev/​caerus/​sdk/​dls/​DlsConflictError.java Adds DLS conflict error.
src/​main/​java/​dev/​caerus/​sdk/​dls/​DlsCore.java Implements DLS transport logic.
src/​main/​java/​dev/​caerus/​sdk/​dls/​DlsError.java Defines base DLS error.
src/​main/​java/​dev/​caerus/​sdk/​dls/​DlsErrors.java Maps DLS errors.
src/​main/​java/​dev/​caerus/​sdk/​dls/​DlsMapping.java Maps DLS models.
src/​main/​java/​dev/​caerus/​sdk/​dls/​DlsNotFoundError.java Adds DLS not-found error.
src/​main/​java/​dev/​caerus/​sdk/​dls/​DlsOperations.java Defines internal DLS operations.
src/​main/​java/​dev/​caerus/​sdk/​dls/​DlsTimeoutError.java Adds DLS timeout error.
src/​main/​java/​dev/​caerus/​sdk/​dls/​DlsValidationError.java Adds DLS validation error.
src/​main/​java/​dev/​caerus/​sdk/​dls/​InMemoryDlsClient.java Implements in-memory DLS.
src/​main/​java/​dev/​caerus/​sdk/​dls/​LockAcquisitionCancelledError.java Adds cancellation error.
src/​main/​java/​dev/​caerus/​sdk/​dls/​LockAlreadyHeldError.java Adds duplicate-lock error.
src/​main/​java/​dev/​caerus/​sdk/​dls/​LockDeniedError.java Adds denial error.
src/​main/​java/​dev/​caerus/​sdk/​dls/​LockHolder.java Models acquired locks.
src/​main/​java/​dev/​caerus/​sdk/​dls/​LockMode.java Defines lock modes.
src/​main/​java/​dev/​caerus/​sdk/​dls/​LockModeMismatchError.java Adds mode error.
src/​main/​java/​dev/​caerus/​sdk/​dls/​LockStatus.java Defines lock states.
src/​main/​java/​dev/​caerus/​sdk/​dls/​LockStatusResponse.java Models lock status.
src/​main/​java/​dev/​caerus/​sdk/​dls/​Transaction.java Models transactions.
src/​main/​java/​dev/​caerus/​sdk/​dls/​TransactionCallback.java Defines transaction callbacks.
src/​main/​java/​dev/​caerus/​sdk/​dls/​TransactionContext.java Defines transaction scope API.
src/​main/​java/​dev/​caerus/​sdk/​dls/​TransactionLockInfo.java Models transaction locks.
src/​main/​java/​dev/​caerus/​sdk/​dls/​TransactionNotActiveError.java Adds inactive-transaction error.
src/​main/​java/​dev/​caerus/​sdk/​dls/​TransactionOptions.java Configures transaction scopes.
src/​main/​java/​dev/​caerus/​sdk/​dls/​TransactionScope.java Manages renewal and cleanup.
src/​main/​java/​dev/​caerus/​sdk/​dls/​TransactionStatusResponse.java Models transaction status.
src/​main/​java/​dev/​caerus/​sdk/​webhooks/​CaerusEvent.java Models webhook envelopes.
src/​main/​java/​dev/​caerus/​sdk/​webhooks/​CaerusSignatureError.java Adds signature error.
src/​main/​java/​dev/​caerus/​sdk/​webhooks/​CaerusWebhookExpiredError.java Adds expiry error.
src/​main/​java/​dev/​caerus/​sdk/​webhooks/​CaerusWebhookPayloadError.java Adds payload error.
src/​main/​java/​dev/​caerus/​sdk/​webhooks/​DeadlockDetectedData.java Models deadlock events.
src/​main/​java/​dev/​caerus/​sdk/​webhooks/​EventData.java Defines event-data hierarchy.
src/​main/​java/​dev/​caerus/​sdk/​webhooks/​EventTypes.java Dispatches event types.
src/​main/​java/​dev/​caerus/​sdk/​webhooks/​JsonFields.java Extracts webhook fields.
src/​main/​java/​dev/​caerus/​sdk/​webhooks/​LockAbandonedData.java Models abandoned locks.
src/​main/​java/​dev/​caerus/​sdk/​webhooks/​LockAcquireFailedData.java Models acquisition failures.
src/​main/​java/​dev/​caerus/​sdk/​webhooks/​LockAcquiredData.java Models lock acquisition.
src/​main/​java/​dev/​caerus/​sdk/​webhooks/​LockReleasedData.java Models lock release.
src/​main/​java/​dev/​caerus/​sdk/​webhooks/​ResourceConfirmedData.java Models confirmations.
src/​main/​java/​dev/​caerus/​sdk/​webhooks/​ResourceCreatedData.java Models resource creation.
src/​main/​java/​dev/​caerus/​sdk/​webhooks/​ResourceDeletedData.java Models resource deletion.
src/​main/​java/​dev/​caerus/​sdk/​webhooks/​ResourceExpiredData.java Models reservation expiry.
src/​main/​java/​dev/​caerus/​sdk/​webhooks/​ResourceExtendedData.java Models reservation extension.
src/​main/​java/​dev/​caerus/​sdk/​webhooks/​ResourceQueuedData.java Models queued reservations.
src/​main/​java/​dev/​caerus/​sdk/​webhooks/​ResourceReleasedData.java Models reservation release.
src/​main/​java/​dev/​caerus/​sdk/​webhooks/​ResourceTakeFailedData.java Models reservation failures.
src/​main/​java/​dev/​caerus/​sdk/​webhooks/​ResourceTakenData.java Models reservations.
src/​main/​java/​dev/​caerus/​sdk/​webhooks/​ResourceUpdatedData.java Models resource updates.
src/​main/​java/​dev/​caerus/​sdk/​webhooks/​TransactionAbortedData.java Models transaction aborts.
src/​main/​java/​dev/​caerus/​sdk/​webhooks/​TransactionCompletedData.java Models transaction completion.
src/​main/​java/​dev/​caerus/​sdk/​webhooks/​TransactionExpiredData.java Models transaction expiry.
src/​main/​java/​dev/​caerus/​sdk/​webhooks/​TransactionRenewedData.java Models transaction renewal.
src/​main/​java/​dev/​caerus/​sdk/​webhooks/​TransactionStartedData.java Models transaction start.
src/​main/​java/​dev/​caerus/​sdk/​webhooks/​UnknownEventData.java Preserves unknown events.
src/​main/​java/​dev/​caerus/​sdk/​webhooks/​Webhooks.java Verifies and decodes webhooks.
src/​test/​java/​dev/​caerus/​sdk/​NoCommentsTest.java Enforces source policy.
src/​test/​java/​dev/​caerus/​sdk/​PublicApiTest.java Guards public API boundaries.
src/​test/​java/​dev/​caerus/​sdk/​dls/​DlsClientOptionsTest.java Tests DLS configuration.
src/​test/​java/​dev/​caerus/​sdk/​dls/​DlsClientRealTest.java Tests DLS transport behavior.
src/​test/​java/​dev/​caerus/​sdk/​dls/​DlsErrorReasonsTest.java Tests DLS error mapping.
src/​test/​java/​dev/​caerus/​sdk/​dls/​DlsMappingTest.java Tests DLS mappings.
src/​test/​java/​dev/​caerus/​sdk/​dls/​DlsMethodsTest.java Tests DLS methods.
src/​test/​java/​dev/​caerus/​sdk/​dls/​DlsMockTest.java Tests in-memory DLS.
src/​test/​java/​dev/​caerus/​sdk/​dls/​DlsOnQueuedTest.java Tests queue callbacks.
src/​test/​java/​dev/​caerus/​sdk/​dls/​DlsTestClients.java Provides DLS test helpers.
src/​test/​java/​dev/​caerus/​sdk/​internal/​GeneratedContractTest.java Guards generated contracts.
src/​test/​java/​dev/​caerus/​sdk/​internal/​RequestIdTest.java Tests request IDs.
src/​test/​java/​dev/​caerus/​sdk/​live/​Live.java Configures live tests.
src/​test/​java/​dev/​caerus/​sdk/​live/​LiveDlsTest.java Verifies hosted DLS.
src/​test/​java/​dev/​caerus/​sdk/​live/​LiveSreTest.java Verifies hosted SRE.
src/​test/​java/​dev/​caerus/​sdk/​sre/​ClientOptionsTest.java Tests SRE configuration.
src/​test/​java/​dev/​caerus/​sdk/​sre/​ErrorReasonsTest.java Tests SRE error mapping.
src/​test/​java/​dev/​caerus/​sdk/​sre/​MethodsTest.java Tests SRE methods.
src/​test/​java/​dev/​caerus/​sdk/​sre/​MockTest.java Tests in-memory SRE.
src/​test/​java/​dev/​caerus/​sdk/​sre/​TimestampsAndTerminalTest.java Tests timestamps and states.
src/​test/​java/​dev/​caerus/​sdk/​sre/​TransportTest.java Tests SRE transport.
src/​test/​java/​dev/​caerus/​sdk/​support/​FakeDlsEngine.java Provides fake DLS server.
src/​test/​java/​dev/​caerus/​sdk/​support/​FakeEngine.java Provides fake SRE server.
src/​test/​java/​dev/​caerus/​sdk/​support/​GrpcErrors.java Builds test gRPC errors.
src/​test/​java/​dev/​caerus/​sdk/​support/​RealTrailers.java Supplies captured trailers.
src/​test/​java/​dev/​caerus/​sdk/​support/​RecordingServer.java Records test RPCs.
src/​test/​java/​dev/​caerus/​sdk/​webhooks/​WebhooksInteropTest.java Tests webhook interoperability.
src/​test/​java/​dev/​caerus/​sdk/​webhooks/​WebhooksTest.java Tests webhook behavior.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +131 to +136
List<TransactionLockInfo> locks = response.getLocksList().stream()
.map(lock -> new TransactionLockInfo(
lock.getNamespace(),
lock.getLockKey(),
DlsMapping.toLockMode(lock.getRequestedModeValue()).orElse(LockMode.EXCLUSIVE),
DlsMapping.toLockStatus(lock.getStatusValue())))

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Se deja así a propósito. El motor trata un modo sin especificar como EXCLUSIVE (ZooKeeperDistributedLockAdapter: safeMode = LockModeDto.EXCLUSIVE cuando llega null o MODE_UNSPECIFIED), así que informarlo como EXCLUSIVE refleja lo que el motor aplicó. Además es lo que hace el SDK de TypeScript, y la API pública tiene que ser la misma en los dos. Queda anotado en docs/paridad.md.

Comment on lines +76 to +79
AcquireLockOptions resolved = options == null ? AcquireLockOptions.none() : options;
if (resolved.signal().map(signal -> signal.aborted()).orElse(false)) {
throw DlsErrors.abortedByUser(null);
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corregido en f00d091. Verificado contra el motor: con la misma clave en la misma transacción devuelve el mismo lockId y fencing token, y con otra clave responde LOCK_ALREADY_HELD_EXCLUSIVELY. El mock ahora hace las dos cosas, y hay un escenario en vivo (anIdempotencyKeyReplaysTheLockAndAnotherKeyIsAlreadyHeld) que lo comprueba contra el motor.

Comment on lines +93 to +95
AbortSignal signal = given.signal()
.or(options::signal)
.orElse(lostController.signal());

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corregido en f00d091. Ahora la espera escucha las dos señales: la propia (o la de las opciones de la transacción) y la de pérdida de la transacción. Tests nuevos: losingTheTransactionAlsoCutsAWaitThatBringsItsOwnSignal e itsOwnSignalStillCutsTheWaitInsideATransaction.

Comment on lines +122 to +123
heartbeat = operations.renewalScheduler().scheduleAtFixedRate(
() -> renew(lifetime), interval, interval, TimeUnit.MILLISECONDS);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corregido en f00d091. Si una renovación sigue en vuelo, el siguiente latido se saltea. Test nuevo: aSlowRenewalIsNeverOverlappedByTheNextOne (renovación de 2,5 s con intervalo de 1 s: nunca hay más de una a la vez).

Comment on lines +40 to +42
public CaerusEvent constructEvent(byte[] payload, String signatureHeader, String secret, long toleranceSeconds) {
String raw = payload == null ? "" : new String(payload, StandardCharsets.UTF_8);
return constructEvent(raw, signatureHeader, secret, toleranceSeconds);

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corregido en f00d091. La firma se calcula sobre timestamp + "." y los bytes crudos; después se decodifica en UTF-8 estricto, y un cuerpo inválido da CaerusWebhookPayloadError. Test nuevo: verifiesTheSignatureOverTheRawBytesEvenWhenTheyAreNotValidUtf8.

Comment thread docs/errores.md Outdated
Comment on lines +92 to +94
Significa que la llamada pasó su deadline. Si el servidor llegó a hacer el trabajo, no se
sabe. Reintentar con la misma clave de idempotencia devuelve el holder que ya existía; mirá
su `status()`, porque puede volver terminado.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Corregido en f00d091: la guía ahora dice que un reintento sobre un holder terminado lanza ConflictError, y que para ver en qué quedó se usa getResourceHolder.

Una espera de acquireLock con senal propia dentro de withTransaction ahora
tambien se corta si la transaccion se pierde; antes la senal propia
reemplazaba a la de la transaccion y la espera quedaba colgada hasta el
deadline. Una renovacion lenta ya no se superpone con la siguiente.

La firma de un webhook se calcula sobre los bytes crudos: un cuerpo autentico
con UTF-8 invalido daba error de firma en vez de error de contenido.

InMemoryDlsClient replica al motor con la clave de idempotencia: la misma
clave en la misma transaccion devuelve el mismo lock y otra clave da
LOCK_ALREADY_HELD_EXCLUSIVELY, verificado contra el motor. La guia de
errores ya no promete que un reintento devuelve un holder terminado: lanza
ConflictError.
@thomyluca
thomyluca merged commit 70a938e into main Oct 3, 2026
2 checks passed
@thomyluca
thomyluca deleted the sdk-bloqueante branch October 3, 2026 16:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants