Skip to content

Goroutine leak in event logger when using --until with dropped contexts #29491

Description

@HindzStark

Issue Description

When fetching events with the --until flag on a system using the file events backend, libpod/events/logfile.go spawns an unmanaged, blocking goroutine that ignores context.Context cancellation.

	if len(options.Until) > 0 {
		// ...
		go func() {
			time.Sleep(time.Until(untilTime))
			if err := t.Stop(); err != nil {
				logrus.Errorf("Stopping logger: %v", err)
			}
		}()
	}

Because time.Sleep is not context-aware, if a client cancels the request (e.g., Ctrl+C on the CLI, or a dropped HTTP connection on the REST API), the goroutine is orphaned and continues sleeping in the background.

If running Podman as a service (podman system service), a client that repeatedly polls GET /events?until= and drops the connection will cause a silent goroutine leak, stacking up sleeping routines and wasting resources.

Steps to reproduce the issue

Steps to reproduce the issue

1. Start the Podman API service (`podman system service`).
2. Send a request to the events endpoint with a far-future until parameter: `curl -v --unix-socket /run/user/1000/podman/podman.sock "http://d/v4.0.0/libpod/events?until=9999h"`
3. Immediately cancel the curl request (press `Ctrl+C`).
4. The background goroutine in `logfile.go` remains asleep, waiting out the 9999h timer even though the context was cancelled.


### Describe the results you received

The goroutine uses an un-interruptible `time.Sleep` which causes a memory/goroutine leak when requests are terminated early by the client.


### Describe the results you expected

The goroutine should use a `timer` and `select` on `ctx.Done()` so it exits immediately when the parent request is cancelled, properly freeing system resources.


### podman info output

```yaml
<details>
<summary>podman info</summary>
time="2026-08-12T16:08:40Z" level=warning msg="\"/\" is not a shared mount, this could cause issues or missing mounts with rootless containers"
host:
  arch: amd64
  buildahVersion: 1.33.7
  cgroupControllers:
  - cpu
  - memory
  - pids
  cgroupManager: cgroupfs
  cgroupVersion: v2
  conmon:
    package: conmon_2.1.10+ds1-1build2_amd64
    path: /usr/bin/conmon
    version: 'conmon version 2.1.10, commit: unknown'
  cpuUtilization:
    idlePercent: 98.71
    systemPercent: 0.3
    userPercent: 0.99
  cpus: 8
  databaseBackend: sqlite
  distribution:
    distribution: ubuntu
    version: "22.04"
  eventLogger: file
  hostname: MSI
  idMappings:
    gidmap:
    - container_id: 0
      host_id: 1000
      size: 1
    - container_id: 1
      host_id: 100000
      size: 65536
    uidmap:
    - container_id: 0
      host_id: 1000
      size: 1
    - container_id: 1
      host_id: 100000
      size: 65536
  kernel: 5.15.153.1-microsoft-standard-WSL2
  linkmode: dynamic
  logDriver: journald
  memFree: 2269925376
  memTotal: 8251031552
  networkBackend: netavark
  networkBackendInfo:
    backend: netavark
    dns:
      package: '"aardvark-dns" is not installed.'
      path: /usr/lib/podman/aardvark-dns
      version: aardvark-dns 1.10.0
    package: '"netavark" is not installed.'
    path: /usr/lib/podman/netavark
    version: netavark 1.10.3
  ociRuntime:
    name: crun
    package: crun_1.14.4-1ubuntu1_amd64
    path: /usr/bin/crun
    version: |-
      crun version 1.14.4
      commit: 260fa110753060f6ee4a8e8e7a027376c72d512a
      rundir: /run/user/1000/crun
      spec: 1.0.0
      +SYSTEMD +SELINUX +APPARMOR +CAP +SECCOMP +EBPF +CRIU +YAJL
  os: linux
  pasture: true
  remoteSocket:
    exists: true
    path: /run/user/1000/podman/podman.sock
  security:
    apparmorEnabled: false
    capabilities: CAP_CHOWN,CAP_DAC_OVERRIDE,CAP_FOWNER,CAP_FSETID,CAP_KILL,CAP_NET_BIND_SERVICE,CAP_SETFCAP,CAP_SETGID,CAP_SETPCAP,CAP_SETUID,CAP_SYS_CHROOT
    rootless: true
    seccompEnabled: true
    seccompProfilePath: /etc/containers/seccomp.json
    selinuxEnabled: false
  slirp4netns:
    executable: /usr/bin/slirp4netns
    package: slirp4netns_1.0.1-2_amd64
    version: |-
      slirp4netns version 1.0.1
      commit: 2011b9a2dc4b4ad44ff9cc3f25c7657929497e74
      libslirp: 4.6.1
      SLIRP_CONFIG_VERSION_MAX: 3
      libseccomp: 2.5.3
  swapFree: 2147483648
  swapTotal: 2147483648
  uptime: 462h 21m 27.67s (Approximately 19.25 days)
plugins:
  authorization: null
  log:
  - k8s-file
  - none
  - passthrough
  - journald
  network:
  - bridge
  - macvlan
  - ipvlan
  volume:
  - local
registries:
  search:
  - registry.fedoraproject.org
  - registry.access.redhat.com
  - docker.io
  - quay.io
store:
  configFile: /home/dhruv/.config/containers/storage.conf
  containerStore:
    number: 1
    paused: 0
    running: 1
    stopped: 0
  graphDriverName: overlay
  graphOptions: {}
  graphRoot: /home/dhruv/.local/share/containers/storage
  graphRootAllocated: 274864197632
  graphRootUsed: 19572428800
  graphStatus:
    Backing Filesystem: extfs
    Native Overlay Diff: "true"
    Supports d_type: "true"
    Supports shifting: "false"
    Supports volatile: "true"
    Using metacopy: "false"
  imageCopyTmpDir: /var/tmp
  imageStore:
    number: 0
  runRoot: /run/user/1000/containers
  transientStore: false
  volumePath: /tmp/podman_temp_root/volumes
version:
  APIVersion: 4.9.3
  Built: 0
  BuiltTime: Thu Jan  1 00:00:00 1970
  GitCommit: ""
  GoVersion: go1.22.2
  Os: linux
  OsArch: linux/amd64
  Version: 4.9.3
</details>

Podman in a container

No

Privileged Or Rootless

Rootless

Upstream Latest Release

Yes

Additional environment details

No response

Additional information

I plan to submit a PR to fix this issue as my third contribution for my LFX Mentorship application. The PR will replace time.Sleep with a time.NewTimer and a select block listening on ctx.Done() to guarantee the goroutine is successfully destroyed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    kind/bugCategorizes issue or PR as related to a bug.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions