Skip to content

Release/v1.61.0 - #4246

Merged
aryanmehrotra merged 51 commits into
mainfrom
release/v1.61.0
Sep 17, 2026
Merged

aryanmehrotra merged 51 commits into
mainfrom
release/v1.61.0

Conversation

@aryanmehrotra

@aryanmehrotra aryanmehrotra commented Sep 16, 2026 •

Copy link
Copy Markdown
Member

Release v1.61.0

🚀 Features

🔹 HTTP QUERY Method (RFC 10008)

QUERY is a safe, idempotent method that puts the query in the request body. It avoids GET's URL-length limit and query strings leaking into logs, without losing safety the way POST does. GoFr now supports it for incoming routes and on the service client:

// inbound
app.QUERY("/search", func(ctx *gofr.Context) (any, error) {
    var q SearchRequest
    if err := ctx.Bind(&q); err != nil {
        return nil, err
    }
    return search(ctx, q)
})

// outbound
resp, err := ctx.GetHTTPService("catalog").Query(ctx, "search", nil, body)

As RFC 10008 requires, a QUERY request with no Content-Type gets 400, and one GoFr cannot decode gets 415, before your handler runs. The 415 is the new typed ErrorUnsupportedMediaType. Unknown paths still return 404. On the client, QUERY gets circuit-breaker and retry handling like GET. The circuit breaker now returns an error for an unrecognised method; before, it quietly returned a nil response.

🔹 Readiness Checks for /.well-known/health

/.well-known/health always answered 200, so a Kubernetes readiness probe on it sent traffic to a pod whose dependencies weren't reachable yet. AddReadinessCheck makes the endpoint answer 503 until your check passes:

// GoFr's own datasource checks must pass, and so must this one
app.AddReadinessCheck(func(ctx *gofr.Context) error {
    return licenseDB.PingContext(ctx)
})

// your check decides alone; GoFr's checks are not run
app.AddReadinessCheck(func(ctx *gofr.Context) error {
    if redisUp(ctx) || sqlUp(ctx) {
        return nil
    }
    return errNoBackingStore
}, gofr.ReplaceFrameworkChecks())

You can register several checks. They run in the order you added them, and the first failure decides. FrameworkReadiness(ctx) returns GoFr's own result, so a replace-mode check can still use it. The error is logged, never written to the response, whose body is just DOWN. With no check registered, the endpoint behaves exactly as before.

🔹 Configurable Metric Cardinality Limit

METRICS_CARDINALITY_LIMIT sets how many attribute sets each OpenTelemetry instrument keeps. Once an instrument passes the limit, extra series are merged into one otel.metric.overflow series, so a label explosion can't overwhelm your backend.

value behavior
unset SDK default (2000, or OTEL_GO_X_CARDINALITY_LIMIT) — unchanged
> 0 that limit; takes precedence over OTEL_GO_X_CARDINALITY_LIMIT
0 or negative unlimited

🔹 Circuit Breaker Open Counter

app_circuit_open_count{service} goes up once each time a circuit actually goes from closed to open. It does not count every failing request that sees the trip, so a burst of concurrent failures still adds exactly one.

🔹 Azure Event Hub Health Check

Health() for Event Hub was a stub that returned an empty status. Container.Health didn't count an empty status as DOWN, so an app that couldn't reach its Event Hub reported UP. It now makes a real connectivity check, limited to 2s, and reports UP/DOWN with backend, eventHub and partitionCount. The 2s limit is enforced by GoFr itself, because azeventhubs ignores the caller's deadline on this call.

🔧 Enhancements

🔹 Concurrent Health Checks

Container.Health used to check each dependency one after another, so the endpoint took as long as all the checks added together. The checks now run in parallel, and callers that arrive at the same time share one set of results:

before after
one /health probe 1605 ms 401 ms
20 concurrent probes 1623 ms, 80 backend calls 402 ms, 4 backend calls

(MySQL, Redis and four HTTP dependencies, each taking 400 ms to answer.)

A panicking check reports its dependency as DOWN instead of crashing the process. Two new settings are both off by default:

config description
HEALTH_CACHE_TTL Reuse a result for this long (5s, 1m) before checking again.
HEALTH_CHECK_TIMEOUT Limit a round of checks (2s). Dependencies that haven't answered are left out, the status is DEGRADED, and the partial result is never cached.

🔹 MQTT Tracing Semantics

MQTT publish and subscribe spans now set SpanKind and the messaging.* attributes, as Kafka, NATS, SQS and Google Pub/Sub already do. The consume span used to start on context.Background() and ended up in a separate trace. It now sits inside the trace of the request that consumed the message. MQTT 3.1.1 has nowhere to carry traceparent, so there is still no link across the broker. With tracing off, publish allocates exactly what it did before.

To match the other providers, MQTT's app_pubsub_subscribe_total_count now counts Subscribe calls, so it lines up with the success counter. It used to count messages arriving.

⚡ Performance

Fewer allocations on every request. Output is byte-identical in each case.

path before after
CORS headers (wildcard config) 5 allocs, 160 B 0 allocs, 0 B
CORS headers (named origins) 6 allocs, 176 B 2 allocs, 32 B
HTTP metrics histogram observation 4 allocs, 424 B 0 allocs, 0 B
JSON response 9 allocs, 288 B 7 allocs, 224 B
RBAC rule resolution (51 rules) 9,684 allocs, 373,669 ns 6 allocs, 1,717 ns
  • CORS: the fixed header values are built once, on the first request, instead of on every response.
  • Metrics: the measurement option is built once for each (route, method, status) and reused. The cache is keyed on the route template and only admits templated routes, so unique unmatched paths can't fill it up.
  • Responder: the response envelope is pooled with its encoder and cleared before it goes back to the pool. The canonical Content-Type value is built once.
  • RBAC: endpoint patterns are compiled once when the config loads. The old code added a route to a shared router on every request, which caused a data race and unbounded growth (0 → 114 routes after 100 requests). RBAC cost no longer grows with the number of rules.

🛠️ Fixes

  • RBAC Wildcard Rules Ignored — Rules with "methods": ["*"], or with no methods, never matched, so the routes they protected let every request through. They are now enforced.

  • Auth Exemption Matched Too Broadly — Paths that merely started with /.well-known, such as /.well-knownprivate, skipped auth and rate limiting. The exemption now requires /.well-known/.

  • Tracer Credentials in Logs — Credentials in TRACER_URL were printed in startup logs. They are now logged as REDACTED.

  • TRACER_URL With a Scheme Exported Nothing — http:// and https:// endpoints were not valid gRPC targets. They now work, and TRACER_INSECURE controls host:port endpoints.

  • Scanner Traffic Hid Real Routes in Metrics — Random unmatched URLs filled the metrics series limit. They now collapse into __unmatched__, so real routes keep their series.

  • SIGTERM During Startup Was Lost — A signal that arrived before the server started left it running until SIGKILL. The server now stops.

  • WebSocket Route Panic — A plain HTTP request to a WebSocket route panicked. It now returns an error.

  • Auto-CRUD Panics and Mangled Names — uint, bool and time.Time fields panicked, and digits were corrupted in table and column names. Both are fixed.

  • SQL Log Duration Unit — SQL query logs now report microseconds, like every other datasource.

  • SFTP/S3 Observability — Failed SFTP opens were logged as SUCCESS, and some operations used the wrong names. Status and labels are now correct.

  • Kafka and Google Pub/Sub Panics — Closing a Kafka client, or subscribing to several Google Pub/Sub topics, could crash with concurrent map access. Both are now synchronized.

  • Dgraph Migrations — Migrations now run inside a transaction.

Full Changelog: v1.60.1...v1.61.0

aryanmehrotra and others added 30 commits September 2, 2026 18:44
chore(metrics): pin gcp exporter to gofr.dev v1.60.1
…ption (#4099)

* fix(middleware): require a path separator in the well-known auth exemption

* test(middleware): cover the rate limiter well-known exemption

* chore(middleware): satisfy goconst and noctx in the well-known check

* docs(auth): describe the separator requirement in the well-known exemption

---------

Co-authored-by: Aryan Mehrotra <aryanmehrotra2000@gmail.com>
Co-authored-by: Umang Mundhra <mundhraumang.02@gmail.com>
Co-authored-by: aryanmehrotra <aryanmehrotra2000@gmail.com>
)

Co-authored-by: Umang Mundhra <mundhraumang.02@gmail.com>
Co-authored-by: Aryan Mehrotra <aryanmehrotra2000@gmail.com>
… writes (#4054) (#4055)

---------

Co-authored-by: Umang Mundhra <mundhraumang.02@gmail.com>
Co-authored-by: Aryan Mehrotra <aryanmehrotra2000@gmail.com>
…pdate (#4153)

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: Aryan Mehrotra <aryanmehrotra2000@gmail.com>
Co-authored-by: Aryan Mehrotra <aryanmehrotra2000@gmail.com>
Co-authored-by: Umang Mundhra <mundhraumang.02@gmail.com>
Co-authored-by: Aryan Mehrotra <aryanmehrotra2000@gmail.com>
… group (#4197)

Closes: #4171

Co-authored-by: Aryan Mehrotra <aryanmehrotra2000@gmail.com>
…4196)

Applied surgically per direct-dependency module (per-module go get + go mod
tidy; no go work sync). All bumps are minor/patch/security — no majors, no
go-redis mock regen needed (miniredis is a test double, not go-redis).

Updates:
- go.opentelemetry.io/otel/sdk 1.45.0 -> 1.46.0 (root, metrics/exporters/gcp, pubsub/nats, pubsub/sqs)
- go.opentelemetry.io/otel/exporters/zipkin 1.44.0 -> 1.46.0 (root)
- go.opentelemetry.io/contrib/detectors/gcp 1.44.0 -> 1.46.0 (metrics/exporters/gcp)
- github.com/aws/aws-sdk-go-v2/config 1.32.37 -> 1.33.3 (file/s3, kv-store/dynamodb, pubsub/sqs, examples/using-s3-filestore)
- github.com/aws/aws-sdk-go-v2/service/dynamodb 1.63.3 -> 1.67.0 (kv-store/dynamodb)
- github.com/aws/aws-sdk-go-v2/service/sqs 1.46.6 -> 1.51.0 (pubsub/sqs)
- github.com/nats-io/nats-server/v2 2.14.5 -> 2.14.6 (pubsub/nats)
- golang.org/x/sync 0.22.0 -> 0.23.0 (root)
- modernc.org/sqlite 1.56.0 -> 1.58.0 (root)
- github.com/alicebob/miniredis/v2 2.38.0 -> 2.39.0 (root, test)
- google.golang.org/grpc 1.83.1 -> 1.83.2 security (root + library modules + examples; pulls golang.org/x/net 0.57.0 -> 0.58.0). examples/using-gcp-metrics is excluded: it is baseline-untidy (excluded from the CI tidy gate) and tidying it to apply grpc would settle unrelated versions.

Closes: #4172, #4173, #4174, #4175, #4176, #4177, #4178, #4179, #4180, #4181, #4182, #4183, #4184, #4185, #4186, #4187, #4188, #4189, #4190, #4191, #4192, #4194

Co-authored-by: Aryan Mehrotra <aryanmehrotra2000@gmail.com>
Co-authored-by: Umang Mundhra <mundhraumang.02@gmail.com>
Co-authored-by: Aryan Mehrotra <aryanmehrotra2000@gmail.com>
…" example (#3876) (#3977)

Co-authored-by: Aryan Mehrotra <aryanmehrotra2000@gmail.com>
…uisite (#3461)

The broken Auth Middleware link this PR also carried has since landed via
#3798, so what remains is:

- "Custom Middleware" was plain text next to the linked Auth Middleware; it now
  points at docs/advanced-guide/middlewares.
- The prerequisite said Go 1.24. Every go.mod in the repo declares go 1.26.0,
  and CI's 1.24/1.25 matrix entries only pass because a setup-go-toolchain step
  auto-upgrades them, so 1.26 is the real floor.

Co-authored-by: Aryan Mehrotra <aryanmehrotra2000@gmail.com>
Co-authored-by: Umang Mundhra <mundhraumang.02@gmail.com>
…3227)

Co-authored-by: Umang Mundhra <mundhraumang.02@gmail.com>
Co-authored-by: Aryan Mehrotra <aryanmehrotra2000@gmail.com>
akshat-kumar-singhal and others added 13 commits September 10, 2026 16:08
…tech (#4199)

Co-authored-by: Aryan Mehrotra <aryanmehrotra2000@gmail.com>
Major version bump (v0 -> v1) of the docs static-server base image.
Consolidated from Dependabot #3990.

Closes: #3990

Co-authored-by: Aryan Mehrotra <aryanmehrotra2000@gmail.com>
…ng patterns deterministically (#3808) (#3934)

Co-authored-by: Aryan Mehrotra <aryanmehrotra2000@gmail.com>
… public (#4208)

quay.io/minio/minio:RELEASE.2025-09-07T16-13-09Z carries the identical manifest
list — sha256:14cea493… , byte-for-byte the digest already pinned — so this
changes the registry and nothing else. The image CI runs is provably the one it
ran on 2026-09-11, and the digest pin protecting the integration guard for #3804
stays intact. Bumping to a newer release instead would have changed two things
at once.
…sts entirely (#4201)

Co-authored-by: Aryan Mehrotra <aryanmehrotra2000@gmail.com>
Comment thread pkg/gofr/otel.go Fixed
Comment thread pkg/gofr/otel.go Fixed
Comment thread pkg/gofr/otel.go Fixed
aryanmehrotra added a commit that referenced this pull request Sep 16, 2026
Since #4205 a scheme-bearing TRACER_URL is a real URL, so it can carry
credentials in userinfo or its query string, and every tracer startup log
wrote it verbatim. Endpoints are now logged through redactURL, the exporter
name is logged as the matched constant, and the raw TRACER_INSECURE and
unsupported TRACE_EXPORTER values are no longer echoed.

This clears CodeQL go/clear-text-logging alerts 179-184 on pkg/gofr/otel.go,
which failed the CodeQL check on the v1.61.0 release PR (#4246).
# Conflicts:
#	pkg/gofr/metrics/exporters/gcp/go.mod
#	pkg/gofr/metrics/exporters/gcp/go.sum
#	pkg/gofr/version/version.go
@aryanmehrotra

Copy link
Copy Markdown
Member Author

The 3 CodeQL go/clear-text-logging comments here (alerts #179, #181, #182, plus #180, #183 and #184 on the same file) are fixed in #4247, where CodeQL passes with none of the 6 alerts on the merge ref. Once #4247 merges into development, I will cherry-pick it onto release/v1.61.0.

The merge conflicts with main are resolved in 8d62e87: version.go stays v1.61.0, and the gcp exporter go.mod/go.sum take the newer development versions. Both sides pin gofr.dev v1.60.1, so #4148 is kept.

@aryanmehrotra

Copy link
Copy Markdown
Member Author

Updated with development in e6195fa (clean merge; the tree now equals development plus the version bump). This brings in two PRs merged since the branch was cut:

Both are now in the release notes under Fixes, with entries under Upgrade Notes. Verified on the merged head: go build ./pkg/gofr/..., the gcp exporter module builds, and tests pass for pkg/gofr, http/middleware, container and metrics/exporters. It still merges cleanly into main.

@aryanmehrotra
aryanmehrotra merged commit dc7f889 into main Sep 17, 2026
88 checks passed
@aryanmehrotra
aryanmehrotra deleted the release/v1.61.0 branch September 17, 2026 14:08
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.