Files
openobserve/web
Hengfei Yang ebdc2f0a4e fix(search): release the admission slot and follower task status on cancellation (#13954)
Paired with o2-enterprise `hf/issue-2491-admission-slot-leak` (same
branch name).

**Stacked on #13953** — base is that branch, so the diff here is just
this change.
Retargets to `main` automatically once #13953 merges.

## Problem

#13953 fixed the wal file locks. `do_get` touches two more trace-id
keyed
resources, and both had the identical defect: release depended on
control flow
reaching a call, inside the window where gRPC cancellation drops the
future.

**The node's admission slot.** Released from three hand-written sites —
the two
error arms in `do_get` and `FlightEncoderStream::drop`. All three are
skipped
when the request is cancelled during plan generation, because the
encoder
stream does not exist yet.

**The follower task status.** In the super-cluster path the entry was
inserted
before plan generation and removed after it:

```rust
if is_super_cluster && !SEARCH_SERVER.contain_key(&trace_id).await {
    SEARCH_SERVER.insert(trace_id.clone(), TaskStatus::new_follower(vec![], false)).await;
}
let result = get_ctx_and_physical_plan(&trace_id, &req).await;   // <-- cancellable
if is_super_cluster && !SEARCH_SERVER.is_leader(&trace_id).await {
    SEARCH_SERVER.remove(&trace_id, false).await;
}
```

Cancel in the middle and the entry stays in the map for the life of the
process. Nothing else removes it: an explicit `cancel_query` would, but
a
timeout or a client disconnect would not.

## Approach

Both move onto the same ownership chain #13953 established.

`SessionGuard` — already armed on the first line of `do_get` and already
carried into `FlightEncoderStream` — now releases the admission slot
too, so
the three call sites collapse into its drop.

The follower task status is registered through an `AsyncDefer` that
lives in
the same scope as plan generation, so it is removed on every exit
including a
cancelled one. It is now removed only when this node registered it,
rather than
whenever the entry is not a leader's: a request can no longer clear an
entry it
did not create. In practice these coincide, since the composite
`{trace_id}-{job_id}`
is unique per request.

### Drive-by

The `physical plan generate error` and `physical plan execution error`
logs sat
*inside* `if get_o2_config().work_group.max_nodes_per_query > 0`, so a
plan
failure was silent unless work groups happened to be configured — and
silent in
every OSS build. They are unconditional now.

## Enterprise side

The paired PR gives `Running` reservations a TTL backstop. They had no
expiry
edge at all, so a slot whose release was lost — this cancellation path,
or a
leader that dies before sending `Release` — was held until the process
restarted. This PR closes the local path; the backstop covers the remote
one,
which no local guard can.

## Verification

- `cargo fmt --all` and the CI clippy command: clean
- Enterprise verified via the `Cargo.toml.openobserve` swap against the
paired
  branch: `cargo check --all-targets` clean, and `cargo clippy --no-deps
-p openobserve-api-grpc --all-targets` clean. The workspace-wide
enterprise
clippy still reports the two pre-existing `cognitive_complexity` errors
in
`core/src/alerts/scheduler/handlers.rs` and `core/src/ofga/mod.rs`,
untouched
  by this change
- `api-grpc` flight tests 21/21

## Also here

Three zh-CN strings whose English is *events* said 活动 (activity).
Unrelated to
the rest of the PR, carried along at review request.

| key | en-US | was | now |
|---|---|---|---|
| `home.docsCountLbl` | Events | 活动 | 事件 |
| `rum.searchEvents` | Search Events | 搜索活动 | 搜索事件 |
| `logs.noEvents.title` | No events found | 未找到任何活动 | 未找到任何事件 |

zh-TW already had 事件 for all three, and every other locale translates
them as
events. `logs.noEvents` also contradicted itself — `descNoFilters`
directly
below the title already said 未找到任何事件.

## Not in this PR

The `QueryManager` map has a `created_at` on every entry but no reaper.
With
this change its entries are removed on cancellation, so it is no longer
known
to grow — but it has no backstop the way the ledger now does.
2026-08-26 09:09:35 +00:00
..
2025-12-04 13:58:09 +05:30
2026-05-28 11:00:49 +00:00
2026-08-18 10:34:04 +00:00
…
…

web

This template should help get you started developing with Vue 3 in Vite.

VSCode + Volar (and disable Vetur) + TypeScript Vue Plugin (Volar).

Type Support for .vue Imports in TS

TypeScript cannot handle type information for .vue imports by default, so we replace the tsc CLI with vue-tsc for type checking. In editors, we need TypeScript Vue Plugin (Volar) to make the TypeScript language service aware of .vue types.

If the standalone TypeScript plugin doesn't feel fast enough to you, Volar has also implemented a Take Over Mode that is more performant. You can enable it by the following steps:

  1. Disable the built-in TypeScript Extension
    1. Run Extensions: Show Built-in Extensions from VSCode's command palette
    2. Find TypeScript and JavaScript Language Features, right click and select Disable (Workspace)
  2. Reload the VSCode window by running Developer: Reload Window from the command palette.

Customize configuration

See Vite Configuration Reference.

Project Setup

npm install

Compile and Hot-Reload for Development

For stand-alone UI development environment, create .env file and which contains below environment variable

VITE_OPENOBSERVE_ENDPOINT=http://localhost:5080/
npm run dev

Type-Check, Compile and Minify for Production

npm run build

Run Unit Tests with Vitest

npm run test:unit

Run End-to-End Tests with Cypress

npm run test:e2e:dev

This runs the end-to-end tests against the Vite development server. It is much faster than the production build.

But it's still recommended to test the production build with test:e2e before deploying (e.g. in CI environments):

npm run build
npm run test:e2e

Lint with ESLint

npm run lint