Skip to content

out_s3: $INDEX sequence index resets on restart because the metadata stream is deleted on shutdown (causes object overwrites) #11987

Description

@dacort

Bug Report

Fluent Bit version: v4.2.2 (also present in v5.0.7 and current master)
Plugin: out_s3
Environment: Linux x86_64; Fluent Bit runs as a sidecar that tails rolled log files and uploads them to S3, with store_dir on a persistent volume that survives process/container restarts.

One caveat is that I'm unsure if this is intentional behavior or not? For context, I'm trying to mirror Spark event logs to S3 similar to this blog post

Configuration (minimal repro)

[INPUT]
    name             tail
    path             /var/log/app/segment_*
    db               /data/flb/tail.db
    read_from_head   on

[OUTPUT]
    name             s3
    match            *
    bucket           my-bucket
    region           us-east-1
    total_file_size  50M
    store_dir        /data/flb/s3
    s3_key_format    /logs/myapp/segment_$INDEX

store_dir (and the tail db) are on a volume that survives restarts.

Expected behavior

Per the docs:

$INDEX ... is saved in the store_dir. If you restart Fluent Bit with the same disk, it can continue incrementing the index from its last value in the previous run.

So after a restart on the same store_dir, the next upload should continue from the last value (e.g. segment_5), and previously uploaded objects should never be overwritten.

Actual behavior

After a graceful restart (SIGTERM) with the same persistent store_dir, $INDEX resets to 0. The next uploads recreate segment_0, segment_1, ... overwriting objects from the previous run. There is no Successfully recovered index. Continuing at index=N line on startup.

Root cause

$INDEX state is stored as a plain file at <store_dir>/<bucket>/sequence/index_metadata/seq_index_<id> (written with fopen/fprintf in init_seq_index() / write_seq_index()), inside an fstore stream named sequence. This file is not a Chunk I/O chunk, and Chunk I/O's scan only registers regular files located directly under a stream directory — cio_scan_stream_files() skips the nested index_metadata/ subdirectory because it is not DT_REG. As a result the sequence fstore stream has zero registered files.

On shutdown, cb_s3_exit()s3_store_exit()flb_fstore_destroy() iterates all streams and deletes any stream with files == 0 via flb_fstore_stream_destroy(stream, FLB_TRUE)cio_stream_delete(), which recursively removes the stream directory. That deletes sequence/index_metadata/seq_index_<id>. On the next start, init_seq_index()'s access(seq_index_file, F_OK) misses and resets $INDEX to 0.

Relevant code (master):

  • plugins/out_s3/s3.cinit_seq_index() stores $INDEX as a raw file; access()-or-reset logic.
  • lib/chunkio/src/cio_scan.ccio_scan_stream_files() only handles DT_REG entries, so the nested index_metadata/ dir is ignored and the stream has 0 files.
  • src/flb_fstore.cflb_fstore_destroy() deletes streams with 0 files (if (files == 0) delete = FLB_TRUE;).
  • plugins/out_s3/s3_store.cs3_store_exit() calls flb_fstore_destroy().

Additional notes

  • Not multipart-specific: both the PutObject and multipart upload paths depend on the same init_seq_index() state file.
  • Confirmed with a marker + inode test: a marker file placed inside sequence/ is gone after a graceful restart, while a marker placed one level above it (still on the same persistent volume) survives — i.e. the volume is healthy; Fluent Bit deletes its own metadata stream. The sequence/ directory comes back with a fresh inode and mtime after the restart.
  • A hard crash (SIGKILL) does not delete it, because cb_s3_exit() / flb_fstore_destroy() only run on graceful shutdown — but typical restarts use SIGTERM, which does.

Proposed fix

Detach the metadata stream reference in s3_store_exit() before flb_fstore_destroy() runs, so the empty-stream cleanup skips it and the persisted $INDEX file survives:

if (ctx->stream_metadata != NULL) {
    flb_fstore_stream_destroy(ctx->stream_metadata, FLB_FALSE);
    ctx->stream_metadata = NULL;
}

I have a fix ready and will open a PR shortly.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions