Repository navigation
A minor release, compatible with 1.0. Upgrade by changing the halyx-bom version to 1.1.0; japicmp checks every published module against 1.0.0, so existing code keeps compiling and running. 1.1.x now gets the security fixes (see SECURITY.md).
Features
-
Kotlin coroutines (#11):
@HalyxListenermethods may besuspend funs, for subscriptions and stream consumers. Returning acks or
commits, and throwing retries, as with any listener. Needskotlinx-coroutines-reactor.- Reactive repositories take
suspendCRUD methods and derived queries, andFlowresults: aFlowquery reads
every match, page by page, and asuspendquery may return aWindow. Entities are@JvmRecord data classes. - Tested on Boot 3.5 (Kotlin 1.9) and Boot 4 (Kotlin 2.3), in memory and on Kafka, SQS and DynamoDB emulators,
withawaitSingleandasFlowover the reactive services.
-
Function invocation (#22):
FunctionInvokerinvokes AWS Lambda functions, Azure Functions and Cloud Run functions by name, with a payload,
configured and per-request headers, and a timeout, throughCloudContext.functionInvoker. Each cloud's login is
handled: IAM on Lambda, an Entra ID token or a function key on Azure, a Google ID token on Cloud Run.- A function that throws raises
UnavailableExceptionon every cloud, a missing oneNotFoundException, and
other statuses map as for every other service. Requests over a cloud's payload or header limit are refused
before they're sent. - Invocations run the function, so they're retried only for functions configured
idempotent; the SDKs retry
others only after throttling or a failure to connect. triggerstarts a Lambda function without waiting for it (FunctionCapability.TRIGGER).async()views, and
ReactiveFunctionInvokerin halyx-reactor.TracingFunctionInvokercarries the trace context into the function, as headers or in Lambda'sClientContext.- Spring Boot:
halyx.functions.<key>registers aFunctionInvokerbean, with a reactive view. - A function conformance kit, run on the memory provider (
InMemoryFunctions), Floci's Lambda, the Azure
Functions host and Google's Functions Framework, with tier 1 real-cloud runs on all three clouds. AzureErrors.fromStatusandGcpErrors.fromStatusmap an HTTP status as the SDK translations do.- The AI skills know functions:
halyx-ai-createplans, writes and tests function calls,halyx-ai-migratemaps
LambdaClientand HTTP calls to Azure Functions and Cloud Run functions, andhalyx-ai-reviewchecks them
(rule C11).
-
Rotated keys (#26):
FunctionConfig.Builder.property(String, Supplier<String>): a property asked for each time it's used. The
Azure function key is asked for on every call, so a rotated key takes effect without a restart.- Spring Boot:
halyx.functions.<key>.secretsreads settings such asazure.functions.keyfrom one of the
halyx.parameter-stores, through its read cache. A missing secret fails the start. - Spring Boot: a
halyx.*property whose${...}placeholder didn't resolve fails the start, naming the property.
Spring leaves such a value as written, so a missing secret was sent as the key and failed every call. - Cosmos DB account keys and Event Grid access keys given as suppliers (
ProviderConfig.property(String, Supplier),
and the same onEventBusConfigandSubscriptionConfig) are asked for everyazure.key-refresh-interval(one
minute by default), and Cosmos DB and Event Grid use a rotated key from the next request. Spring Boot:
secretson providers, event buses and subscriptions. - Service Bus and App Configuration connection strings stay read once: their SDKs copy the key when the client is
built. The docs recommend Entra ID login for keys that rotate. - Cache and Kafka passwords given as suppliers (
CacheAuth.password(Supplier),
StreamAuth.password(mechanism, username, Supplier)) are asked for each time a connection logs in: Redis on
new connections and reconnects, Kafka also when the broker has open connections log in again. Spring Boot:
auth.secreton caches, the cache manager and stream clusters, as on databases, including for Spring for
Apache Kafka. - Docs: keeping keys for other services in a parameter store, including a store on another cloud.
- Spring Boot: a blank
propertiesvalue no longer counts as set next to asecretsentry for the same setting,
as a blank value is unset everywhere else. - Real-cloud tests on Azure (tier 1): a function key, a Cosmos DB key and an Event Grid key rotated in Key Vault
while the clients stay open, and the function key through Spring Bootsecrets.
-
Function error text (#31): a failed invocation's exception
has aFunctionErrorcause with what the function reported, whole: Lambda'serrorMessage,errorTypeand
payload, or an HTTP function's status and body.FunctionError.of(e)finds it. The exception messages are
unchanged and still cut long bodies. On the memory provider, a handler's exception is now theFunctionError's
cause rather than theUnavailableException's.
Build
- API compatibility checks (#4):
mvn verifycompares each
published module with 1.0.0 from Maven Central using japicmp, and fails on a binary- or source-incompatible change
to the public API, the provider SPI included. CI runs it on every push. - Dependency scanning: a workflow scans SBOMs of every published module and the samples with OSV-Scanner on
every push and pull request, and weekly.osv-scanner.tomllists the findings Halyx can't fix itself, with their
reasons, in place of the Snyk policy file.
Dependencies
- OpenTelemetry API 1.67.0, held above the 1.62.0 the Google Cloud libraries bring, for a security fix found
with OSV-Scanner. The portable orders samples take the same override, and the Boot 3.5 one also log4j 2.25.5. - Tested on Spring Boot 4.1.2 and Google Cloud libraries 26.91.0 (Parameter Manager 0.44.0).
- Spring Boot 3.5 applications: Boot 3.5.16, the newest 3.5 release, manages Spring Framework 6.2.19, for which
OSV lists advisories fixed only in Spring Framework 7. Halyx doesn't bring Spring Framework; the version is the
application's Boot's.