From 290b9fa70526ffdb733159c2d21544c0fd7b5d8d Mon Sep 17 00:00:00 2001 From: stroblme Date: Thu, 15 Oct 2026 09:53:19 +0200 Subject: [PATCH] Superuser route to flush the metrics collector now POST /observability/flush handles what the collector has queued and writes it, so the soak harness no longer sleeps FLUSH_INTERVAL_S before clearing its own rows. --- backend/fluksio/api/routes/observability.py | 24 ++++++++++++-- backend/fluksio/flow/metrics.py | 17 ++++++++++ backend/fluksio/main.py | 4 ++- backend/scripts/soak.py | 19 +++++++---- .../tests/api/routes/test_observability.py | 32 ++++++++++++++++++- docs/code/api.md | 1 + frontend/src/client/sdk.gen.ts | 18 ++++++++++- frontend/src/client/types.gen.ts | 2 ++ 8 files changed, 106 insertions(+), 11 deletions(-) diff --git a/backend/fluksio/api/routes/observability.py b/backend/fluksio/api/routes/observability.py index f72733c..ad315f4 100644 --- a/backend/fluksio/api/routes/observability.py +++ b/backend/fluksio/api/routes/observability.py @@ -19,12 +19,17 @@ from sqlalchemy import select as sa_select from sqlmodel import col, select from fluksio import __version__ -from fluksio.api.deps import FlowControllerDep, SessionDep, get_current_user +from fluksio.api.deps import ( + FlowControllerDep, + SessionDep, + get_current_active_superuser, + get_current_user, +) from fluksio.api.routes.runs import elapsed_ms from fluksio.core.config import settings from fluksio.flow.controller import NodeStatus from fluksio.flow.pipeline import ADVISORY_ISSUES -from fluksio.models import EngineEvent, FlowRun, MetricBucket +from fluksio.models import EngineEvent, FlowRun, Message, MetricBucket router = APIRouter( prefix="/observability", @@ -508,3 +513,18 @@ async def read_dead_letters( if controller.execution is None: return [] return await run_in_threadpool(controller.execution.queue.dead_letters, limit) + + +@router.post( + "/flush", + response_model=Message, + dependencies=[Depends(get_current_active_superuser)], +) +async def flush_metrics(request: Request) -> Any: + """Write what the metrics collector holds now, not at its next interval. + + For tooling that reads or clears these tables right after causing events, + such as the soak harness clearing its own rows. + """ + await request.app.state.metrics_collector.flush_now() + return Message(message="Metrics flushed") diff --git a/backend/fluksio/flow/metrics.py b/backend/fluksio/flow/metrics.py index 6eacba9..b2f7d3f 100644 --- a/backend/fluksio/flow/metrics.py +++ b/backend/fluksio/flow/metrics.py @@ -103,6 +103,7 @@ class MetricsCollector: # held with the time it arrived so an unpaired one does not stay put. self._tracebacks: dict[tuple[str, str], tuple[float, str]] = {} self._last_prune = 0.0 + self._queue: asyncio.Queue[dict[str, Any]] | None = None # ------------------------------------------------------------------------- # The loop @@ -112,6 +113,7 @@ class MetricsCollector: """Consume the bus until cancelled, flushing on a fixed interval.""" last = time.monotonic() async with self._events.subscribe() as queue: + self._queue = queue while True: # A busy bus never idles, so the flush is on a deadline rather # than on the timeout alone. @@ -129,6 +131,21 @@ class MetricsCollector: await self.flush() last = time.monotonic() + async def flush_now(self) -> None: + """Write what has been heard so far, without waiting for the interval. + + Events the bus has handed over and the loop has not reached yet are + taken first, so whoever caused an event and then asks for a flush finds + it written. + """ + while self._queue is not None and not self._queue.empty(): + event = self._queue.get_nowait() + try: + self.handle(event) + except Exception: + logger.exception("Could not record %s", event.get("type")) + await self.flush() + # ------------------------------------------------------------------------- # Accumulating # ------------------------------------------------------------------------- diff --git a/backend/fluksio/main.py b/backend/fluksio/main.py index 39833df..bb0836b 100644 --- a/backend/fluksio/main.py +++ b/backend/fluksio/main.py @@ -384,7 +384,9 @@ async def lifespan(app: FastAPI) -> AsyncIterator[None]: _background(watchdog.run(), "loop-watchdog") _background(alerts.run(), "alert-manager") - _background(MetricsCollector(event_bus).run(), "metrics-collector") + # On the app so a superuser can ask it to flush now. + app.state.metrics_collector = MetricsCollector(event_bus) + _background(app.state.metrics_collector.run(), "metrics-collector") _background(_sweep_artifacts(artifacts, controller), "artifact-gc") _background(_trim_volatile(volatile), "artifact-ring") await controller.start() diff --git a/backend/scripts/soak.py b/backend/scripts/soak.py index dc1f83d..8ba85ac 100644 --- a/backend/scripts/soak.py +++ b/backend/scripts/soak.py @@ -36,7 +36,6 @@ from typing import Any import httpx from fluksio.core.config import settings -from fluksio.flow.metrics import FLUSH_INTERVAL_S log = logging.getLogger("soak") @@ -374,6 +373,14 @@ def create_flow( log.info("created flow '%s'", name) +def flush_metrics(client: httpx.Client) -> None: + """Have the metrics collector write what it holds now.""" + try: + client.post("/api/v1/observability/flush").raise_for_status() + except httpx.HTTPError as exc: + log.error("could not flush the metrics collector: %s", exc) + + def delete_flows(client: httpx.Client) -> None: for name in FLOWS: try: @@ -887,11 +894,11 @@ def cleanup(client: httpx.Client | None) -> None: delete_flows(client) clear_redis() - # Deleting a flow publishes an audit event of its own, and the metrics - # collector buffers what it hears for up to FLUSH_INTERVAL_S before writing - # it. Clearing the tables any sooner races that flush and leaves the rows - # this very cleanup caused. - time.sleep(FLUSH_INTERVAL_S + 5.0) + # Deleting a flow publishes an audit event of its own, which the metrics + # collector holds until its next flush. Clearing the tables before it is + # written would leave the rows this very cleanup caused. + if client is not None: + flush_metrics(client) clear_observability() diff --git a/backend/tests/api/routes/test_observability.py b/backend/tests/api/routes/test_observability.py index 6e8f963..77dafba 100644 --- a/backend/tests/api/routes/test_observability.py +++ b/backend/tests/api/routes/test_observability.py @@ -1,9 +1,11 @@ +import time from datetime import UTC, datetime, timedelta from fastapi.testclient import TestClient -from sqlmodel import Session +from sqlmodel import Session, select from fluksio.core.config import settings +from fluksio.flow.events import event_bus from fluksio.models import EngineEvent, FlowRun, MetricBucket PREFIX = f"{settings.API_V1_STR}/observability" @@ -482,3 +484,31 @@ def test_a_node_failing_on_every_call_makes_the_summary_degraded( assert body["nodes"]["failing"] == 1 (problem,) = [p for p in body["problems"] if "failing" in p] assert "house.calc" in problem and "house.old" not in problem + + +def test_a_superuser_can_flush_the_collector_now( + client: TestClient, + superuser_token_headers: dict[str, str], + normal_user_token_headers: dict[str, str], + db: Session, +) -> None: + """Whoever reads or clears the tables need not wait out the interval.""" + event_bus.publish( + { + "type": "audit", + "action": "flushed", + "flow": FLOW, + "user": "a@example.com", + "ts": time.time(), + } + ) + url = f"{PREFIX}/flush" + assert client.post(url, headers=normal_user_token_headers).status_code == 403 + assert client.post(url, headers=superuser_token_headers).status_code == 200 + + written = db.exec( + select(EngineEvent).where( + EngineEvent.flow == FLOW, EngineEvent.detail == "flushed" + ) + ).all() + assert len(written) == 1 diff --git a/docs/code/api.md b/docs/code/api.md index 3d6df91..a418e09 100644 --- a/docs/code/api.md +++ b/docs/code/api.md @@ -208,6 +208,7 @@ Connector state keys can also be listed and cleared by a superuser; see | `GET` | `/observability/summary` | health and engine version; always returns `200` | | `GET` | `/observability/timeseries`, `/observability/flows` | execution metrics or flow rollups | | `GET` | `/observability/runs`, `/observability/events`, `/observability/dead-letter` | cascades, events, or abandoned work | +| `POST` | `/observability/flush` | write buffered metrics and events now; superuser only | | `GET` | `/utils/health/` | deep health check; fails on loop or state-backend problems | | `GET` | `/workers`, `/workers/resources` | attached workers and resource availability | | `GET`, `POST` | `/workers/tokens` | list or mint worker credentials; superuser only | diff --git a/frontend/src/client/sdk.gen.ts b/frontend/src/client/sdk.gen.ts index fbad4f3..66ce387 100644 --- a/frontend/src/client/sdk.gen.ts +++ b/frontend/src/client/sdk.gen.ts @@ -3,7 +3,7 @@ import type { CancelablePromise } from './core/CancelablePromise'; import { OpenAPI } from './core/OpenAPI'; import { request as __request } from './core/request'; -import type { AiReadAiConfigResponse, AiUpdateAiConfigData, AiUpdateAiConfigResponse, AiDeleteAiConfigResponse, AiListAiModelsData, AiListAiModelsResponse, AiReadAiStatusResponse, AiReadControlNodesResponse, AiReadChatResponse, AiChatData, AiChatResponse, AiClearChatResponse, AlertsReadAlertsConfigResponse, AlertsSaveAlertsConfigData, AlertsSaveAlertsConfigResponse, AlertsReadWebpushKeyResponse, AlertsAddWebpushSubscriptionData, AlertsAddWebpushSubscriptionResponse, AlertsRemoveWebpushSubscriptionData, AlertsRemoveWebpushSubscriptionResponse, AlertsTestChannelData, AlertsTestChannelResponse, ArtifactsPutArtifactData, ArtifactsPutArtifactResponse, ArtifactsGetArtifactData, ArtifactsGetArtifactResponse, CloudReadStatusResponse, CloudEnrollData, CloudEnrollResponse, CloudAddRemoteUserData, CloudAddRemoteUserResponse, CloudDisconnectResponse, ConnectorsReadConnectorStateData, ConnectorsReadConnectorStateResponse, ConnectorsClearConnectorStateData, ConnectorsClearConnectorStateResponse, ConnectorsDeleteConnectorStateData, ConnectorsDeleteConnectorStateResponse, DashboardsReadDashboardsResponse, DashboardsReadDashboardData, DashboardsReadDashboardResponse, DashboardsCreateDashboardData, DashboardsCreateDashboardResponse, DashboardsSaveDashboardData, DashboardsSaveDashboardResponse, DashboardsDeleteDashboardData, DashboardsDeleteDashboardResponse, DashboardsGenerateResultsDashboardData, DashboardsGenerateResultsDashboardResponse, DashboardsPublishDashboardData, DashboardsPublishDashboardResponse, DashboardsDiscardDashboardDraftData, DashboardsDiscardDashboardDraftResponse, DashboardsRenameDashboardData, DashboardsRenameDashboardResponse, FlavorsReadFlavorsResponse, FlavorsCreateFlavorData, FlavorsCreateFlavorResponse, FlavorsUpdateFlavorData, FlavorsUpdateFlavorResponse, FlavorsDeleteFlavorData, FlavorsDeleteFlavorResponse, FlowsReadFlowsResponse, FlowsReadNodeTypesResponse, FlowsReadGraphResponse, FlowsReadLibraryResponse, FlowsDeleteSharedNodeData, FlowsDeleteSharedNodeResponse, FlowsReadFlowData, FlowsReadFlowResponse, FlowsSaveFlowData, FlowsSaveFlowResponse, FlowsDeleteFlowData, FlowsDeleteFlowResponse, FlowsPublishFlowData, FlowsPublishFlowResponse, FlowsDiscardDraftData, FlowsDiscardDraftResponse, FlowsRenameFlowData, FlowsRenameFlowResponse, FlowsReadNodeSourceData, FlowsReadNodeSourceResponse, FlowsSaveNodeSourceData, FlowsSaveNodeSourceResponse, FlowsShareNodeData, FlowsShareNodeResponse, FlowsUnshareNodeData, FlowsUnshareNodeResponse, FlowsStartFlowData, FlowsStartFlowResponse, FlowsStopFlowData, FlowsStopFlowResponse, FlowsPauseFlowData, FlowsPauseFlowResponse, FlowsResumeFlowData, FlowsResumeFlowResponse, FlowsStepFlowData, FlowsStepFlowResponse, FlowsValidateFlowData, FlowsValidateFlowResponse, FlowsRunFlowData, FlowsRunFlowResponse, FlowsTriggerNodeData, FlowsTriggerNodeResponse, FlowsCancelNodeData, FlowsCancelNodeResponse, FlowsAcknowledgeNodeErrorData, FlowsAcknowledgeNodeErrorResponse, FlowsReadFlowStateData, FlowsReadFlowStateResponse, FlowsReadMessageHistoryData, FlowsReadMessageHistoryResponse, FlowsIssueSocketTicketResponse, LoginLoginAccessTokenData, LoginLoginAccessTokenResponse, LoginTestTokenResponse, LoginRecoverPasswordData, LoginRecoverPasswordResponse, LoginResetPasswordData, LoginResetPasswordResponse, LoginRecoverPasswordHtmlContentData, LoginRecoverPasswordHtmlContentResponse, MessagesReadMessagesResponse, MessagesPublishMessageData, MessagesPublishMessageResponse, MessagesReadMessageHistoryData, MessagesReadMessageHistoryResponse, ModulesReadModulesResponse, ModulesApplyModulesData, ModulesApplyModulesResponse, ModulesRefreshModulesResponse, OauthRegisterClientData, OauthRegisterClientResponse, OauthAuthorizeValidateData, OauthAuthorizeValidateResponse, OauthAuthorizeData, OauthAuthorizeResponse, OauthTokenData, OauthTokenResponse, OauthReadClientsResponse, OauthRevokeClientData, OauthRevokeClientResponse, ObservabilityReadSummaryResponse, ObservabilityReadTimeseriesData, ObservabilityReadTimeseriesResponse, ObservabilityReadFlowRollupsData, ObservabilityReadFlowRollupsResponse, ObservabilityReadRunsData, ObservabilityReadRunsResponse, ObservabilityReadEventsData, ObservabilityReadEventsResponse, ObservabilityReadDeadLettersData, ObservabilityReadDeadLettersResponse, PanelsReadPanelsResponse, PanelsSavePanelsData, PanelsSavePanelsResponse, PanelsStartPairingResponse, PanelsPollPairingData, PanelsPollPairingResponse, PanelsPendingDeviceData, PanelsPendingDeviceResponse, PanelsApprovePairingData, PanelsApprovePairingResponse, PanelsUnpairPanelData, PanelsUnpairPanelResponse, PanelsReadPanelData, PanelsReadPanelResponse, PrivateCreateUserData, PrivateCreateUserResponse, RunsCreateRunData, RunsCreateRunResponse, RunsCreateSweepData, RunsCreateSweepResponse, RunsImportRunsData, RunsImportRunsResponse, RunsReadRunsData, RunsReadRunsResponse, RunsDeleteRunsData, RunsDeleteRunsResponse, RunsReadOverviewResponse, RunsExportMetricsData, RunsExportMetricsResponse, RunsExportRunsData, RunsExportRunsResponse, RunsReadMetricNamesData, RunsReadMetricNamesResponse, RunsReadRunData, RunsReadRunResponse, RunsDeleteRunData, RunsDeleteRunResponse, RunsCancelRunData, RunsCancelRunResponse, RunsRetryRunData, RunsRetryRunResponse, RunsReadMetricsData, RunsReadMetricsResponse, RunsCompareMetricData, RunsCompareMetricResponse, SearchReadSearchIndexResponse, SecretsReadSecretsResponse, SecretsSaveSecretData, SecretsSaveSecretResponse, SecretsDeleteSecretData, SecretsDeleteSecretResponse, UsersReadUsersData, UsersReadUsersResponse, UsersCreateUserData, UsersCreateUserResponse, UsersReadUserMeResponse, UsersDeleteUserMeResponse, UsersUpdateUserMeData, UsersUpdateUserMeResponse, UsersUpdatePasswordMeData, UsersUpdatePasswordMeResponse, UsersRegisterUserData, UsersRegisterUserResponse, UsersReadUserByIdData, UsersReadUserByIdResponse, UsersUpdateUserData, UsersUpdateUserResponse, UsersDeleteUserData, UsersDeleteUserResponse, UtilsTestEmailData, UtilsTestEmailResponse, UtilsReadConfigResponse, UtilsHealthCheckResponse, UtilsHealthResponse, WorkersReadWorkersResponse, WorkersReadResourcesResponse, WorkersReadTokensResponse, WorkersIssueTokenData, WorkersIssueTokenResponse, WorkersRevokeTokenData, WorkersRevokeTokenResponse, WorkersReadRuntimeResponse } from './types.gen'; +import type { AiReadAiConfigResponse, AiUpdateAiConfigData, AiUpdateAiConfigResponse, AiDeleteAiConfigResponse, AiListAiModelsData, AiListAiModelsResponse, AiReadAiStatusResponse, AiReadControlNodesResponse, AiReadChatResponse, AiChatData, AiChatResponse, AiClearChatResponse, AlertsReadAlertsConfigResponse, AlertsSaveAlertsConfigData, AlertsSaveAlertsConfigResponse, AlertsReadWebpushKeyResponse, AlertsAddWebpushSubscriptionData, AlertsAddWebpushSubscriptionResponse, AlertsRemoveWebpushSubscriptionData, AlertsRemoveWebpushSubscriptionResponse, AlertsTestChannelData, AlertsTestChannelResponse, ArtifactsPutArtifactData, ArtifactsPutArtifactResponse, ArtifactsGetArtifactData, ArtifactsGetArtifactResponse, CloudReadStatusResponse, CloudEnrollData, CloudEnrollResponse, CloudAddRemoteUserData, CloudAddRemoteUserResponse, CloudDisconnectResponse, ConnectorsReadConnectorStateData, ConnectorsReadConnectorStateResponse, ConnectorsClearConnectorStateData, ConnectorsClearConnectorStateResponse, ConnectorsDeleteConnectorStateData, ConnectorsDeleteConnectorStateResponse, DashboardsReadDashboardsResponse, DashboardsReadDashboardData, DashboardsReadDashboardResponse, DashboardsCreateDashboardData, DashboardsCreateDashboardResponse, DashboardsSaveDashboardData, DashboardsSaveDashboardResponse, DashboardsDeleteDashboardData, DashboardsDeleteDashboardResponse, DashboardsGenerateResultsDashboardData, DashboardsGenerateResultsDashboardResponse, DashboardsPublishDashboardData, DashboardsPublishDashboardResponse, DashboardsDiscardDashboardDraftData, DashboardsDiscardDashboardDraftResponse, DashboardsRenameDashboardData, DashboardsRenameDashboardResponse, FlavorsReadFlavorsResponse, FlavorsCreateFlavorData, FlavorsCreateFlavorResponse, FlavorsUpdateFlavorData, FlavorsUpdateFlavorResponse, FlavorsDeleteFlavorData, FlavorsDeleteFlavorResponse, FlowsReadFlowsResponse, FlowsReadNodeTypesResponse, FlowsReadGraphResponse, FlowsReadLibraryResponse, FlowsDeleteSharedNodeData, FlowsDeleteSharedNodeResponse, FlowsReadFlowData, FlowsReadFlowResponse, FlowsSaveFlowData, FlowsSaveFlowResponse, FlowsDeleteFlowData, FlowsDeleteFlowResponse, FlowsPublishFlowData, FlowsPublishFlowResponse, FlowsDiscardDraftData, FlowsDiscardDraftResponse, FlowsRenameFlowData, FlowsRenameFlowResponse, FlowsReadNodeSourceData, FlowsReadNodeSourceResponse, FlowsSaveNodeSourceData, FlowsSaveNodeSourceResponse, FlowsShareNodeData, FlowsShareNodeResponse, FlowsUnshareNodeData, FlowsUnshareNodeResponse, FlowsStartFlowData, FlowsStartFlowResponse, FlowsStopFlowData, FlowsStopFlowResponse, FlowsPauseFlowData, FlowsPauseFlowResponse, FlowsResumeFlowData, FlowsResumeFlowResponse, FlowsStepFlowData, FlowsStepFlowResponse, FlowsValidateFlowData, FlowsValidateFlowResponse, FlowsRunFlowData, FlowsRunFlowResponse, FlowsTriggerNodeData, FlowsTriggerNodeResponse, FlowsCancelNodeData, FlowsCancelNodeResponse, FlowsAcknowledgeNodeErrorData, FlowsAcknowledgeNodeErrorResponse, FlowsReadFlowStateData, FlowsReadFlowStateResponse, FlowsReadMessageHistoryData, FlowsReadMessageHistoryResponse, FlowsIssueSocketTicketResponse, LoginLoginAccessTokenData, LoginLoginAccessTokenResponse, LoginTestTokenResponse, LoginRecoverPasswordData, LoginRecoverPasswordResponse, LoginResetPasswordData, LoginResetPasswordResponse, LoginRecoverPasswordHtmlContentData, LoginRecoverPasswordHtmlContentResponse, MessagesReadMessagesResponse, MessagesPublishMessageData, MessagesPublishMessageResponse, MessagesReadMessageHistoryData, MessagesReadMessageHistoryResponse, ModulesReadModulesResponse, ModulesApplyModulesData, ModulesApplyModulesResponse, ModulesRefreshModulesResponse, OauthRegisterClientData, OauthRegisterClientResponse, OauthAuthorizeValidateData, OauthAuthorizeValidateResponse, OauthAuthorizeData, OauthAuthorizeResponse, OauthTokenData, OauthTokenResponse, OauthReadClientsResponse, OauthRevokeClientData, OauthRevokeClientResponse, ObservabilityReadSummaryResponse, ObservabilityReadTimeseriesData, ObservabilityReadTimeseriesResponse, ObservabilityReadFlowRollupsData, ObservabilityReadFlowRollupsResponse, ObservabilityReadRunsData, ObservabilityReadRunsResponse, ObservabilityReadEventsData, ObservabilityReadEventsResponse, ObservabilityReadDeadLettersData, ObservabilityReadDeadLettersResponse, ObservabilityFlushMetricsResponse, PanelsReadPanelsResponse, PanelsSavePanelsData, PanelsSavePanelsResponse, PanelsStartPairingResponse, PanelsPollPairingData, PanelsPollPairingResponse, PanelsPendingDeviceData, PanelsPendingDeviceResponse, PanelsApprovePairingData, PanelsApprovePairingResponse, PanelsUnpairPanelData, PanelsUnpairPanelResponse, PanelsReadPanelData, PanelsReadPanelResponse, PrivateCreateUserData, PrivateCreateUserResponse, RunsCreateRunData, RunsCreateRunResponse, RunsCreateSweepData, RunsCreateSweepResponse, RunsImportRunsData, RunsImportRunsResponse, RunsReadRunsData, RunsReadRunsResponse, RunsDeleteRunsData, RunsDeleteRunsResponse, RunsReadOverviewResponse, RunsExportMetricsData, RunsExportMetricsResponse, RunsExportRunsData, RunsExportRunsResponse, RunsReadMetricNamesData, RunsReadMetricNamesResponse, RunsReadRunData, RunsReadRunResponse, RunsDeleteRunData, RunsDeleteRunResponse, RunsCancelRunData, RunsCancelRunResponse, RunsRetryRunData, RunsRetryRunResponse, RunsReadMetricsData, RunsReadMetricsResponse, RunsCompareMetricData, RunsCompareMetricResponse, SearchReadSearchIndexResponse, SecretsReadSecretsResponse, SecretsSaveSecretData, SecretsSaveSecretResponse, SecretsDeleteSecretData, SecretsDeleteSecretResponse, UsersReadUsersData, UsersReadUsersResponse, UsersCreateUserData, UsersCreateUserResponse, UsersReadUserMeResponse, UsersDeleteUserMeResponse, UsersUpdateUserMeData, UsersUpdateUserMeResponse, UsersUpdatePasswordMeData, UsersUpdatePasswordMeResponse, UsersRegisterUserData, UsersRegisterUserResponse, UsersReadUserByIdData, UsersReadUserByIdResponse, UsersUpdateUserData, UsersUpdateUserResponse, UsersDeleteUserData, UsersDeleteUserResponse, UtilsTestEmailData, UtilsTestEmailResponse, UtilsReadConfigResponse, UtilsHealthCheckResponse, UtilsHealthResponse, WorkersReadWorkersResponse, WorkersReadResourcesResponse, WorkersReadTokensResponse, WorkersIssueTokenData, WorkersIssueTokenResponse, WorkersRevokeTokenData, WorkersRevokeTokenResponse, WorkersReadRuntimeResponse } from './types.gen'; export class AiService { /** @@ -1907,6 +1907,22 @@ export class ObservabilityService { } }); } + + /** + * Flush Metrics + * Write what the metrics collector holds now, not at its next interval. + * + * For tooling that reads or clears these tables right after causing events, + * such as the soak harness clearing its own rows. + * @returns Message Successful Response + * @throws ApiError + */ + public static flushMetrics(): CancelablePromise { + return __request(OpenAPI, { + method: 'POST', + url: '/api/v1/observability/flush' + }); + } } export class PanelsService { diff --git a/frontend/src/client/types.gen.ts b/frontend/src/client/types.gen.ts index 778f84a..7258c8b 100644 --- a/frontend/src/client/types.gen.ts +++ b/frontend/src/client/types.gen.ts @@ -2001,6 +2001,8 @@ export type ObservabilityReadDeadLettersData = { export type ObservabilityReadDeadLettersResponse = (Array); +export type ObservabilityFlushMetricsResponse = (Message); + export type PanelsReadPanelsResponse = (PanelsPublic); export type PanelsSavePanelsData = {