Prometheus · Arazzo Workflow

Prometheus Delete Series and Reclaim the Space

Version 1.0.0

Preview what a selector matches, delete it, clean the tombstones, and verify.

1 workflow 2 source APIs 1 provider
View Spec View on GitHub AlertingMetricsMonitoringObservabilityTime SeriesArazzoWorkflows

Provider

prometheus

Workflows

delete-series-reclaim-space
Safely delete matching series and force the space to be reclaimed.
Both admin endpoints require the --web.enable-admin-api flag and return 403 without it. The preview step is not optional in practice — a selector that is broader than intended deletes far more than expected, and there is no undo.
6 steps inputs: end, seriesSelector, start outputs: matchedSeries, numSeriesAfter, numSeriesBefore, remainingSeries
1
previewSeries
querySeries
Resolve the selector to the exact label sets it matches. This is the last chance to catch a selector that is broader than intended, and the count here is precisely what the delete will destroy.
2
measureBefore
getTsdbStatus
Record the TSDB head statistics before the deletion so the reclaimed series count can be shown rather than assumed.
3
deleteSeries
deleteTsdbSeries
Create deletion tombstones for the matched series. This returns 204 and the data becomes unqueryable immediately, but nothing has actually left the disk yet.
4
cleanTombstones
cleanTombstones
Force the tombstoned data off disk rather than waiting for the next natural compaction. This triggers a compaction of every block carrying tombstones and is the step that actually reclaims the space.
5
verifyDeleted
querySeries
Re-run the preview selector and confirm it now matches nothing, proving the deletion took effect rather than silently failing.
6
measureAfter
getTsdbStatus
Read the TSDB head statistics again so the before and after series counts quantify what the deletion actually reclaimed.

Source API Descriptions

Arazzo Workflow Specification

Raw ↑
arazzo: 1.0.1
info:
  title: Prometheus Delete Series and Reclaim the Space
  summary: Preview what a selector matches, delete it, clean the tombstones, and verify.
  description: >-
    Deleting series is the answer to a leaked secret in a label value, a
    cardinality explosion from a bad instrumentation deploy, or a data subject
    request. It is also irreversible, which is why this workflow previews the
    selector before acting on it. The delete only writes tombstones; the data
    stays on disk until a compaction removes it, so the workflow explicitly
    cleans the tombstones and then re-runs the preview to prove the series are
    gone. Every step spells out its request inline so the flow can be read and
    executed without opening the underlying OpenAPI description.
  version: 1.0.0
sourceDescriptions:
- name: httpApi
  url: ../openapi/prometheus-http-api-openapi.yml
  type: openapi
- name: managementApi
  url: ../openapi/prometheus-management-api-openapi.yml
  type: openapi
workflows:
- workflowId: delete-series-reclaim-space
  summary: Safely delete matching series and force the space to be reclaimed.
  description: >-
    Both admin endpoints require the --web.enable-admin-api flag and return 403
    without it. The preview step is not optional in practice — a selector that
    is broader than intended deletes far more than expected, and there is no
    undo.
  inputs:
    type: object
    required:
    - seriesSelector
    properties:
      seriesSelector:
        type: string
        description: >-
          The series selector identifying what to delete (e.g.
          http_requests_total{job="deprecated-api"}). Verify this against the
          preview before trusting it.
      start:
        type: string
        description: >-
          Start of the deletion time range. Defaults to the minimum possible
          time when omitted, meaning all history.
      end:
        type: string
        description: >-
          End of the deletion time range. Defaults to the maximum possible time
          when omitted, meaning all future data already ingested.
  steps:
  - stepId: previewSeries
    description: >-
      Resolve the selector to the exact label sets it matches. This is the last
      chance to catch a selector that is broader than intended, and the count
      here is precisely what the delete will destroy.
    operationId: querySeries
    parameters:
    - name: "match[]"
      in: query
      value:
      - $inputs.seriesSelector
    - name: start
      in: query
      value: $inputs.start
    - name: end
      in: query
      value: $inputs.end
    - name: limit
      in: query
      value: 1000
    successCriteria:
    - condition: $statusCode == 200
    - condition: $response.body#/status == "success"
    outputs:
      matchedSeries: $response.body#/data
      firstSeries: $response.body#/data/0
    onSuccess:
    - name: seriesMatched
      type: goto
      stepId: measureBefore
      criteria:
      - context: $response.body
        condition: $.data.length > 0
        type: jsonpath
    - name: nothingMatched
      type: end
      criteria:
      - context: $response.body
        condition: $.data.length == 0
        type: jsonpath
  - stepId: measureBefore
    description: >-
      Record the TSDB head statistics before the deletion so the reclaimed
      series count can be shown rather than assumed.
    operationId: getTsdbStatus
    parameters:
    - name: limit
      in: query
      value: 10
    successCriteria:
    - condition: $statusCode == 200
    - condition: $response.body#/status == "success"
    outputs:
      numSeriesBefore: $response.body#/data/headStats/numSeries
      chunkCountBefore: $response.body#/data/headStats/chunkCount
  - stepId: deleteSeries
    description: >-
      Create deletion tombstones for the matched series. This returns 204 and
      the data becomes unqueryable immediately, but nothing has actually left
      the disk yet.
    operationId: deleteTsdbSeries
    parameters:
    - name: "match[]"
      in: query
      value:
      - $inputs.seriesSelector
    - name: start
      in: query
      value: $inputs.start
    - name: end
      in: query
      value: $inputs.end
    successCriteria:
    - condition: $statusCode == 204
  - stepId: cleanTombstones
    description: >-
      Force the tombstoned data off disk rather than waiting for the next
      natural compaction. This triggers a compaction of every block carrying
      tombstones and is the step that actually reclaims the space.
    operationId: cleanTombstones
    successCriteria:
    - condition: $statusCode == 204
  - stepId: verifyDeleted
    description: >-
      Re-run the preview selector and confirm it now matches nothing, proving
      the deletion took effect rather than silently failing.
    operationId: querySeries
    parameters:
    - name: "match[]"
      in: query
      value:
      - $inputs.seriesSelector
    - name: start
      in: query
      value: $inputs.start
    - name: end
      in: query
      value: $inputs.end
    successCriteria:
    - condition: $statusCode == 200
    - condition: $response.body#/status == "success"
    outputs:
      remainingSeries: $response.body#/data
  - stepId: measureAfter
    description: >-
      Read the TSDB head statistics again so the before and after series counts
      quantify what the deletion actually reclaimed.
    operationId: getTsdbStatus
    parameters:
    - name: limit
      in: query
      value: 10
    successCriteria:
    - condition: $statusCode == 200
    - condition: $response.body#/status == "success"
    outputs:
      numSeriesAfter: $response.body#/data/headStats/numSeries
      chunkCountAfter: $response.body#/data/headStats/chunkCount
  outputs:
    matchedSeries: $steps.previewSeries.outputs.matchedSeries
    remainingSeries: $steps.verifyDeleted.outputs.remainingSeries
    numSeriesBefore: $steps.measureBefore.outputs.numSeriesBefore
    numSeriesAfter: $steps.measureAfter.outputs.numSeriesAfter