{
  "schema_version": 3,
  "app": "seafile",
  "display_name": "Seafile",
  "upstream_repo": "https://github.com/haiwen/seafile-server",
  "docs_url": "https://manual.seafile.com/13.0/setup/setup_ce_by_docker/",
  "status": "ok",
  "summary": {
    "primary_service": "seafile",
    "app_version": "13.0.28",
    "app_version_pinned": true,
    "runs": 3,
    "publishable": true,
    "publishable_note": null,
    "idle_total_mem_mib": 616.28,
    "idle_total_cpu_pct": 1.81,
    "peak_total_mem_mib": 904.61,
    "peak_is_under_load": true,
    "startup_seconds": 17.5,
    "startup_peak_total_mem_mib": 620.1,
    "settled": true,
    "settle_seconds_used": 122.8,
    "peak_max_mib": 911.35,
    "sizing_peak_mib": 911.35,
    "idle_mem_mib": {
      "median": 616.28,
      "min": 590.22,
      "max": 758.82,
      "values": [
        758.82,
        616.28,
        590.22
      ]
    },
    "idle_cpu_pct": {
      "median": 1.81,
      "min": 1.52,
      "max": 1.91,
      "values": [
        1.81,
        1.91,
        1.52
      ]
    },
    "peak_mem_mib": {
      "median": 904.61,
      "min": 876.15,
      "max": 911.35,
      "values": [
        911.35,
        904.61,
        876.15
      ]
    },
    "startup_peak_mem_mib": {
      "median": 620.1,
      "min": 590.33,
      "max": 760.89,
      "values": [
        760.89,
        620.1,
        590.33
      ]
    },
    "startup_s": {
      "median": 17.5,
      "min": 17.5,
      "max": 17.6,
      "values": [
        17.6,
        17.5,
        17.5
      ]
    },
    "settled_after_healthy_s": {
      "median": 125.3,
      "min": 124.3,
      "max": 128.4,
      "values": [
        128.4,
        125.3,
        124.3
      ]
    },
    "settled_runs": 3,
    "per_service": {
      "db": {
        "idle_mem_mib": {
          "median": 132.6,
          "min": 132.49,
          "max": 132.77,
          "values": [
            132.77,
            132.6,
            132.49
          ]
        },
        "peak_mem_mib": {
          "median": 133.9,
          "min": 133.8,
          "max": 134.1,
          "values": [
            133.9,
            134.1,
            133.8
          ]
        }
      },
      "redis": {
        "idle_mem_mib": {
          "median": 9.01,
          "min": 8.97,
          "max": 9.08,
          "values": [
            8.97,
            9.01,
            9.08
          ]
        },
        "peak_mem_mib": {
          "median": 9.02,
          "min": 9.01,
          "max": 9.04,
          "values": [
            9.04,
            9.02,
            9.01
          ]
        }
      },
      "seafile": {
        "idle_mem_mib": {
          "median": 474.66,
          "min": 448.65,
          "max": 617.08,
          "values": [
            617.08,
            474.66,
            448.65
          ]
        },
        "peak_mem_mib": {
          "median": 761.5,
          "min": 733.7,
          "max": 768.7,
          "values": [
            768.7,
            761.5,
            733.7
          ]
        }
      }
    },
    "variance_flag": null,
    "representative_run": 2,
    "cpu_models": [
      "AMD EPYC 9V45 96-Core Processor"
    ],
    "cpu_model_mismatch": false,
    "rule": "idle = median of the run idle means; peak = median of the run peaks (highest simultaneous total, under load when the app has a load step); peak_max_mib = highest run peak; sizing_peak_mib = highest over runs of max(run peak, run startup peak); variance_flag when max/min over runs is above 1.5 for idle or peak."
  },
  "run": {
    "started_at": "2026-10-16T03:19:35Z",
    "date": "2026-10-16",
    "harness_version": "3.0.0",
    "runs_requested": 3,
    "docker_host": null,
    "remote": false,
    "runs_completed": 3
  },
  "host": {
    "label": "github-actions ubuntu-latest (2 vCPU, 8 GB)",
    "ci": {
      "runs_on": "ubuntu-latest",
      "runner_environment": "github-hosted",
      "runner_os": "Linux",
      "runner_arch": "X64",
      "image_os": "ubuntu24",
      "image_version": "20261012.334.1"
    },
    "cpu_model": "AMD EPYC 9V45 96-Core Processor",
    "cpu_model_note": null,
    "cores": 2,
    "mem_total_mib": 7938,
    "kernel": "6.17.0-1022-azure",
    "os": "Ubuntu 24.04.5 LTS",
    "arch": "x86_64",
    "oci_arch": "amd64",
    "docker_server_version": "28.0.4",
    "docker_client_version": "28.0.4",
    "compose_client_version": "2.38.2",
    "storage_driver": "overlay2",
    "containerd_image_store": false,
    "source": "docker info + throwaway container reading /proc/cpuinfo on the daemon host",
    "compose_note": "Compose runs on the client machine; Docker server fields are from the daemon host"
  },
  "helper_images": {
    "curlimages/curl:latest": {
      "pulled_as": "curlimages/curl:latest",
      "digest": "curlimages/curl@sha256:a134550be58ab783810e613ae96fd253c38f7bdd16d9bf9be350700c7a29ac06"
    },
    "python:3.12-slim": {
      "pulled_as": "python:3.12-slim",
      "digest": "python@sha256:a6e34c598f2467ed0e9a8d349809fcd8b5c603269512df273a0bb1784edc11b1"
    }
  },
  "pull_seconds": 47.9,
  "finished_at": "2026-10-16T03:29:46Z",
  "elapsed_seconds": 610.7,
  "services": {
    "db": {
      "image_ref": "mariadb:10.11",
      "image_repo": "mariadb",
      "image_tag": "10.11",
      "digest": "sha256:7db29378d4fdab73f8123bbc2b48905c90d1a4b00cf848b028f1e81e623257f2",
      "digest_note": null,
      "version": "10.11.19",
      "version_source": "label:org.opencontainers.image.version",
      "version_pinned": true,
      "version_note": null,
      "resolved_tag": "10.11",
      "resolved_tag_note": null,
      "image_size": {
        "unpacked_mb": 327.0,
        "unpacked_source": "docker image ls Size: unpacked image on the daemon host, rounded by docker to 3 significant figures",
        "compressed_mb": 104.2,
        "compressed_source": "sum of compressed layer sizes in the registry manifest for linux/amd64",
        "compressed_null_reason": null,
        "unit_note": "MB = 10^6 bytes. unpacked = disk used on the host; compressed = what is downloaded"
      },
      "compose_image": "mariadb:10.11",
      "compose_comment": "sha256:7db29378d4fdab73f8123bbc2b48905c90d1a4b00cf848b028f1e81e623257f2  (version 10.11.19, from label:org.opencontainers.image.version)",
      "restart_count": 0,
      "oom_killed": false
    },
    "redis": {
      "image_ref": "redis",
      "image_repo": "redis",
      "image_tag": "latest",
      "digest": "sha256:2c2dff791878316e3b083188be0d578423b24813cdda5de0e80ea4f7b3e6bfd6",
      "digest_note": null,
      "version": "8.10.2",
      "version_source": "exec",
      "version_pinned": true,
      "version_note": null,
      "resolved_tag": "8.10.2",
      "resolved_tag_note": null,
      "image_size": {
        "unpacked_mb": 146.0,
        "unpacked_source": "docker image ls Size: unpacked image on the daemon host, rounded by docker to 3 significant figures",
        "compressed_mb": 55.6,
        "compressed_source": "sum of compressed layer sizes in the registry manifest for linux/amd64",
        "compressed_null_reason": null,
        "unit_note": "MB = 10^6 bytes. unpacked = disk used on the host; compressed = what is downloaded"
      },
      "compose_image": "redis:8.10.2",
      "compose_comment": "sha256:2c2dff791878316e3b083188be0d578423b24813cdda5de0e80ea4f7b3e6bfd6  (version 8.10.2, from exec)",
      "restart_count": 0,
      "oom_killed": false
    },
    "seafile": {
      "image_ref": "seafileltd/seafile-mc:13.0.28",
      "image_repo": "seafileltd/seafile-mc",
      "image_tag": "13.0.28",
      "digest": "sha256:b0c90832126bf432db908449f1bb450211e6bbf75a2193bab3399e2a9636eccf",
      "digest_note": null,
      "version": "13.0.28",
      "version_source": "exec",
      "version_pinned": true,
      "version_note": "version taken from the running app (prefer_exec), not from the image label",
      "resolved_tag": "13.0.28",
      "resolved_tag_note": null,
      "image_size": {
        "unpacked_mb": 1650.0,
        "unpacked_source": "docker image ls Size: unpacked image on the daemon host, rounded by docker to 3 significant figures",
        "compressed_mb": 560.2,
        "compressed_source": "sum of compressed layer sizes in the registry manifest for linux/amd64",
        "compressed_null_reason": null,
        "unit_note": "MB = 10^6 bytes. unpacked = disk used on the host; compressed = what is downloaded"
      },
      "compose_image": "seafileltd/seafile-mc:13.0.28",
      "compose_comment": "sha256:b0c90832126bf432db908449f1bb450211e6bbf75a2193bab3399e2a9636eccf  (version 13.0.28, from exec)",
      "restart_count": 0,
      "oom_killed": false
    }
  },
  "runs": [
    {
      "run": 1,
      "started_at": "2026-10-16T03:20:29Z",
      "host": {
        "label": "github-actions ubuntu-latest (2 vCPU, 8 GB)",
        "ci": {
          "runs_on": "ubuntu-latest",
          "runner_environment": "github-hosted",
          "runner_os": "Linux",
          "runner_arch": "X64",
          "image_os": "ubuntu24",
          "image_version": "20261012.334.1"
        },
        "cpu_model": "AMD EPYC 9V45 96-Core Processor",
        "cpu_model_note": null,
        "cores": 2,
        "mem_total_mib": 7938,
        "kernel": "6.17.0-1022-azure",
        "os": "Ubuntu 24.04.5 LTS",
        "arch": "x86_64",
        "oci_arch": "amd64",
        "docker_server_version": "28.0.4",
        "docker_client_version": "28.0.4",
        "compose_client_version": "2.38.2",
        "storage_driver": "overlay2",
        "containerd_image_store": false,
        "source": "docker info + throwaway container reading /proc/cpuinfo on the daemon host",
        "compose_note": "Compose runs on the client machine; Docker server fields are from the daemon host"
      },
      "date": "2026-10-16",
      "startup": {
        "seconds": 17.6,
        "ok": true,
        "checks": [
          {
            "type": "container",
            "ok": true,
            "ready_after_s": 17.6,
            "detail": "shb-seafile-seafile-1=running/healthy, shb-seafile-db-1=running/healthy, shb-seafile-redis-1=running/healthy"
          }
        ],
        "up_command_seconds": 6.0,
        "definition": "wall clock from starting `docker compose up -d` until every health check passed; checks poll every 0.5 s from a throwaway container on the compose network, so resolution is about +/- 1 s"
      },
      "versions": {
        "db": "10.11.19",
        "redis": "8.10.2",
        "seafile": "13.0.28"
      },
      "setup": [
        {
          "exit_code": 0,
          "duration_s": 1.4,
          "reported": {
            "seafile_version": "13.0.28",
            "library_name": "loadtest",
            "library_id": "971feacc-03a4-479b-bd38-5230e3aeb92e",
            "library_created": true,
            "upload_link_ok": true
          },
          "output_tail": [
            "GET /api2/ping/ -> HTTP 200 \"pong\"",
            "GET /api2/server-info/ -> HTTP 200 version 13.0.28",
            "POST /api2/auth-token/ -> HTTP 200",
            "POST /api2/repos/ -> HTTP 200",
            "GET upload-link -> HTTP 200"
          ],
          "description": "Log in to the Web API with the admin account (POST /api2/auth-token/), create the library the load step uploads into (POST /api2/repos/), check that it is listed and that an upload address can be requested. Reports the server version Seafile gives."
        }
      ],
      "idle": {
        "per_service": {
          "db": {
            "samples": 11,
            "mem_mean_mib": 132.77,
            "mem_max_mib": 133.0,
            "cpu_mean_pct": 0.48,
            "cpu_max_pct": 2.61
          },
          "redis": {
            "samples": 11,
            "mem_mean_mib": 8.97,
            "mem_max_mib": 9.21,
            "cpu_mean_pct": 0.4,
            "cpu_max_pct": 1.91
          },
          "seafile": {
            "samples": 11,
            "mem_mean_mib": 617.08,
            "mem_max_mib": 617.7,
            "cpu_mean_pct": 0.94,
            "cpu_max_pct": 3.16
          }
        },
        "total": {
          "samples": 11,
          "dropped_for_total": 0,
          "mem_mean_mib": 758.82,
          "mem_max_mib": 759.49,
          "cpu_mean_pct": 1.81,
          "cpu_max_pct": 6.32
        },
        "window_seconds": 30.2,
        "series": [
          {
            "t_offset_s": 0.0,
            "total_mem_mib": 758.74,
            "total_cpu_pct": 1.48
          },
          {
            "t_offset_s": 3.0,
            "total_mem_mib": 758.76,
            "total_cpu_pct": 3.26
          },
          {
            "t_offset_s": 6.0,
            "total_mem_mib": 758.81,
            "total_cpu_pct": 0.24
          },
          {
            "t_offset_s": 9.1,
            "total_mem_mib": 758.47,
            "total_cpu_pct": 0.24
          },
          {
            "t_offset_s": 12.1,
            "total_mem_mib": 759.49,
            "total_cpu_pct": 6.32
          },
          {
            "t_offset_s": 15.1,
            "total_mem_mib": 758.78,
            "total_cpu_pct": 1.51
          },
          {
            "t_offset_s": 18.1,
            "total_mem_mib": 758.53,
            "total_cpu_pct": 0.23
          },
          {
            "t_offset_s": 21.1,
            "total_mem_mib": 759.03,
            "total_cpu_pct": 2.9
          },
          {
            "t_offset_s": 24.2,
            "total_mem_mib": 758.65,
            "total_cpu_pct": 0.26
          },
          {
            "t_offset_s": 27.2,
            "total_mem_mib": 758.87,
            "total_cpu_pct": 2.1
          },
          {
            "t_offset_s": 30.2,
            "total_mem_mib": 758.91,
            "total_cpu_pct": 1.42
          }
        ]
      },
      "settle": {
        "settled": true,
        "mode": "detected",
        "settle_seconds_used": 122.8,
        "settle_started_after_healthy_s": 5.6,
        "params": {
          "window_seconds": 60,
          "threshold_pct": 2.0,
          "threshold_min_mib": 10.0,
          "min_seconds": 120,
          "max_seconds": 600
        },
        "last_window": {
          "n": 20,
          "mean_mib": 758.57,
          "min_mib": 758.14,
          "max_mib": 758.8,
          "spread_mib": 0.66,
          "threshold_mib": 15.17
        },
        "rechecks": 0,
        "rule": "settled = over the last window_seconds the stack total varied (max - min) by less than max(threshold_pct of the window mean, threshold_min_mib); not before min_seconds, at the latest max_seconds, both counted from the end of the setup steps; the idle window must also be flat and agree with it. If max_seconds passes without settling, settled=false and the idle window is measured anyway."
      },
      "startup_peak": {
        "per_service_mem_mib": {
          "db": 133.2,
          "redis": 13.84,
          "seafile": 618.8
        },
        "total_mem_mib": 760.89,
        "samples": 43,
        "note": "highest value across docker stats samples (about one every 2-3 s) from healthy until the stack settled; shorter spikes between samples are not seen"
      },
      "timeline": {
        "step_s": 10,
        "t0": "healthy",
        "offsets_s": [
          10,
          20,
          30,
          40,
          50,
          60,
          70,
          80,
          90,
          100,
          110,
          120,
          130,
          140,
          150,
          160
        ],
        "total_mem_mib": [
          614.0,
          757.9,
          757.8,
          758.0,
          758.2,
          759.5,
          758.5,
          758.5,
          758.5,
          758.6,
          758.7,
          758.6,
          758.5,
          758.7,
          759.0,
          758.8
        ],
        "per_service_mem_mib": {
          "db": [
            132.7,
            132.9,
            132.9,
            133.0,
            132.9,
            133.0,
            132.8,
            132.8,
            132.8,
            132.7,
            132.9,
            132.7,
            132.6,
            132.7,
            132.8,
            132.9
          ],
          "redis": [
            10.6,
            9.0,
            9.1,
            9.0,
            9.1,
            9.2,
            9.1,
            9.1,
            9.1,
            9.2,
            9.1,
            9.0,
            9.0,
            9.0,
            8.9,
            8.9
          ],
          "seafile": [
            470.7,
            615.9,
            615.9,
            616.1,
            616.2,
            617.3,
            616.6,
            616.6,
            616.6,
            616.7,
            616.7,
            616.9,
            616.9,
            617.0,
            617.2,
            617.0
          ]
        }
      },
      "load": {
        "per_service": {
          "db": {
            "samples": 4,
            "mem_mean_mib": 133.75,
            "mem_max_mib": 133.9,
            "cpu_mean_pct": 7.38,
            "cpu_max_pct": 29.47
          },
          "redis": {
            "samples": 4,
            "mem_mean_mib": 8.99,
            "mem_max_mib": 9.04,
            "cpu_mean_pct": 0.78,
            "cpu_max_pct": 1.92
          },
          "seafile": {
            "samples": 4,
            "mem_mean_mib": 765.7,
            "mem_max_mib": 768.7,
            "cpu_mean_pct": 23.33,
            "cpu_max_pct": 83.8
          }
        },
        "total": {
          "samples": 4,
          "dropped_for_total": 0,
          "mem_mean_mib": 908.44,
          "mem_max_mib": 911.35,
          "cpu_mean_pct": 31.49,
          "cpu_max_pct": 114.33
        },
        "description": "The same load as the Nextcloud and ownCloud tests, through Seafile's own Web API. One user (the admin), over plain HTTP on the Compose network, one request at a time, each on a new connection. A Python script generates the same 103 random files (100 small ones of 1 KB to 1 MB, about 50 MB together, and three of 50 MB; same seed, same names, same order), creates a folder in the library, asks for one upload address for that folder (GET upload-link) and uploads the files to it with one multipart POST each, lists the folder with one GET of the directory, and downloads five files (three small, two large; one request for the download address and one for the file each) and checks their SHA-256. About 200 MB in total. The web API is used instead of WebDAV because it is what Seafile's web interface, mobile apps and scripts use; WebDAV is a separate, optional component that is off by default in Seafile 13. No browser, no sync client (Seafile's desktop client uses its own block-based sync protocol, which is not exercised), no chunked upload, no thumbnails, no sharing.",
        "duration_s": 4.1,
        "window": "from LAB_MARK load_start (or step start) until 2 s after the step ended",
        "reported_by_script": {
          "api": "seafile web api (api2) and the upload-api/files addresses it returns",
          "files_uploaded": 103,
          "small_files": 100,
          "large_files": 3,
          "bytes_uploaded": 194456599,
          "upload_seconds": 1.5,
          "listing_entries": 103,
          "listing_seconds": 0.01,
          "files_downloaded": 5,
          "bytes_downloaded": 101451451,
          "download_seconds": 0.5,
          "downloads_sha256_match": true,
          "requests": {
            "create_folder": {
              "sent": 1,
              "ok": 1,
              "statuses": {
                "201": 1
              }
            },
            "upload_link": {
              "sent": 1,
              "ok": 1,
              "statuses": {
                "200": 1
              }
            },
            "upload": {
              "sent": 103,
              "ok": 103,
              "statuses": {
                "200": 103
              }
            },
            "list": {
              "sent": 1,
              "ok": 1,
              "statuses": {
                "200": 1
              }
            },
            "download_link": {
              "sent": 5,
              "ok": 5,
              "statuses": {
                "200": 5
              }
            },
            "download": {
              "sent": 5,
              "ok": 5,
              "statuses": {
                "200": 5
              }
            }
          },
          "requests_total": 116,
          "requests_failed": 0
        },
        "output_tail": [
          "generated 103 files (100 small, 3 large), 194.5 MB",
          "uploaded 103 of 103 files, 194.5 MB in 1.5s; statuses {'200': 103}",
          "GET dir HTTP 200: 103 files in 0.01s; names and sizes match the upload: True",
          "downloaded 5 of 5 files, 101.5 MB in 0.5s"
        ],
        "series": [
          {
            "t_offset_s": 0.0,
            "total_mem_mib": 899.94,
            "total_cpu_pct": 114.33
          },
          {
            "t_offset_s": 2.0,
            "total_mem_mib": 911.13,
            "total_cpu_pct": 9.29
          },
          {
            "t_offset_s": 4.0,
            "total_mem_mib": 911.35,
            "total_cpu_pct": 2.13
          },
          {
            "t_offset_s": 6.0,
            "total_mem_mib": 911.34,
            "total_cpu_pct": 0.21
          }
        ],
        "series_start_offset_s": 1.3,
        "peak_note": "peak = highest value seen across docker stats samples (about one every 2-3 s); shorter spikes between samples are not seen"
      },
      "container_end_state": {
        "db": {
          "restart_count": 0,
          "oom_killed": false
        },
        "redis": {
          "restart_count": 0,
          "oom_killed": false
        },
        "seafile": {
          "restart_count": 0,
          "oom_killed": false
        }
      },
      "teardown": {
        "done": true,
        "volumes_removed": true,
        "images_removed": false,
        "error": null
      },
      "warnings": [],
      "finished_at": "2026-10-16T03:23:37Z",
      "elapsed_seconds": 187.8
    },
    {
      "run": 2,
      "started_at": "2026-10-16T03:23:37Z",
      "host": {
        "label": "github-actions ubuntu-latest (2 vCPU, 8 GB)",
        "ci": {
          "runs_on": "ubuntu-latest",
          "runner_environment": "github-hosted",
          "runner_os": "Linux",
          "runner_arch": "X64",
          "image_os": "ubuntu24",
          "image_version": "20261012.334.1"
        },
        "cpu_model": "AMD EPYC 9V45 96-Core Processor",
        "cpu_model_note": null,
        "cores": 2,
        "mem_total_mib": 7938,
        "kernel": "6.17.0-1022-azure",
        "os": "Ubuntu 24.04.5 LTS",
        "arch": "x86_64",
        "oci_arch": "amd64",
        "docker_server_version": "28.0.4",
        "docker_client_version": "28.0.4",
        "compose_client_version": "2.38.2",
        "storage_driver": "overlay2",
        "containerd_image_store": false,
        "source": "docker info + throwaway container reading /proc/cpuinfo on the daemon host",
        "compose_note": "Compose runs on the client machine; Docker server fields are from the daemon host"
      },
      "date": "2026-10-16",
      "startup": {
        "seconds": 17.5,
        "ok": true,
        "checks": [
          {
            "type": "container",
            "ok": true,
            "ready_after_s": 17.5,
            "detail": "shb-seafile-seafile-1=running/healthy, shb-seafile-redis-1=running/healthy, shb-seafile-db-1=running/healthy"
          }
        ],
        "up_command_seconds": 5.9,
        "definition": "wall clock from starting `docker compose up -d` until every health check passed; checks poll every 0.5 s from a throwaway container on the compose network, so resolution is about +/- 1 s"
      },
      "versions": {
        "db": "10.11.19",
        "redis": "8.10.2",
        "seafile": "13.0.28"
      },
      "setup": [
        {
          "exit_code": 0,
          "duration_s": 1.0,
          "reported": {
            "seafile_version": "13.0.28",
            "library_name": "loadtest",
            "library_id": "06a36b42-e392-44df-8632-02b3d9e85a57",
            "library_created": true,
            "upload_link_ok": true
          },
          "output_tail": [
            "GET /api2/ping/ -> HTTP 200 \"pong\"",
            "GET /api2/server-info/ -> HTTP 200 version 13.0.28",
            "POST /api2/auth-token/ -> HTTP 200",
            "POST /api2/repos/ -> HTTP 200",
            "GET upload-link -> HTTP 200"
          ],
          "description": "Log in to the Web API with the admin account (POST /api2/auth-token/), create the library the load step uploads into (POST /api2/repos/), check that it is listed and that an upload address can be requested. Reports the server version Seafile gives."
        }
      ],
      "idle": {
        "per_service": {
          "db": {
            "samples": 11,
            "mem_mean_mib": 132.6,
            "mem_max_mib": 132.9,
            "cpu_mean_pct": 0.24,
            "cpu_max_pct": 2.6
          },
          "redis": {
            "samples": 11,
            "mem_mean_mib": 9.01,
            "mem_max_mib": 9.16,
            "cpu_mean_pct": 0.59,
            "cpu_max_pct": 2.0
          },
          "seafile": {
            "samples": 11,
            "mem_mean_mib": 474.66,
            "mem_max_mib": 476.4,
            "cpu_mean_pct": 1.08,
            "cpu_max_pct": 3.41
          }
        },
        "total": {
          "samples": 11,
          "dropped_for_total": 0,
          "mem_mean_mib": 616.28,
          "mem_max_mib": 617.88,
          "cpu_mean_pct": 1.91,
          "cpu_max_pct": 6.12
        },
        "window_seconds": 30.2,
        "series": [
          {
            "t_offset_s": 0.0,
            "total_mem_mib": 616.2,
            "total_cpu_pct": 0.27
          },
          {
            "t_offset_s": 3.0,
            "total_mem_mib": 616.0,
            "total_cpu_pct": 1.44
          },
          {
            "t_offset_s": 6.0,
            "total_mem_mib": 616.26,
            "total_cpu_pct": 3.24
          },
          {
            "t_offset_s": 9.1,
            "total_mem_mib": 615.96,
            "total_cpu_pct": 3.36
          },
          {
            "t_offset_s": 12.1,
            "total_mem_mib": 615.72,
            "total_cpu_pct": 0.29
          },
          {
            "t_offset_s": 15.1,
            "total_mem_mib": 616.3,
            "total_cpu_pct": 6.12
          },
          {
            "t_offset_s": 18.1,
            "total_mem_mib": 616.2,
            "total_cpu_pct": 1.45
          },
          {
            "t_offset_s": 21.1,
            "total_mem_mib": 616.13,
            "total_cpu_pct": 0.28
          },
          {
            "t_offset_s": 24.2,
            "total_mem_mib": 616.0,
            "total_cpu_pct": 2.07
          },
          {
            "t_offset_s": 27.2,
            "total_mem_mib": 616.39,
            "total_cpu_pct": 0.32
          },
          {
            "t_offset_s": 30.2,
            "total_mem_mib": 617.88,
            "total_cpu_pct": 2.17
          }
        ]
      },
      "settle": {
        "settled": true,
        "mode": "detected",
        "settle_seconds_used": 122.8,
        "settle_started_after_healthy_s": 2.5,
        "params": {
          "window_seconds": 60,
          "threshold_pct": 2.0,
          "threshold_min_mib": 10.0,
          "min_seconds": 120,
          "max_seconds": 600
        },
        "last_window": {
          "n": 20,
          "mean_mib": 614.32,
          "min_mib": 613.18,
          "max_mib": 616.2,
          "spread_mib": 3.01,
          "threshold_mib": 12.29
        },
        "rechecks": 0,
        "rule": "settled = over the last window_seconds the stack total varied (max - min) by less than max(threshold_pct of the window mean, threshold_min_mib); not before min_seconds, at the latest max_seconds, both counted from the end of the setup steps; the idle window must also be flat and agree with it. If max_seconds passes without settling, settled=false and the idle window is measured anyway."
      },
      "startup_peak": {
        "per_service_mem_mib": {
          "db": 133.0,
          "redis": 9.21,
          "seafile": 478.2
        },
        "total_mem_mib": 620.1,
        "samples": 42,
        "note": "highest value across docker stats samples (about one every 2-3 s) from healthy until the stack settled; shorter spikes between samples are not seen"
      },
      "timeline": {
        "step_s": 10,
        "t0": "healthy",
        "offsets_s": [
          10,
          20,
          30,
          40,
          50,
          60,
          70,
          80,
          90,
          100,
          110,
          120,
          130,
          140,
          150,
          160
        ],
        "total_mem_mib": [
          612.5,
          612.5,
          612.7,
          612.7,
          614.6,
          613.3,
          613.4,
          613.6,
          613.8,
          613.8,
          613.8,
          615.6,
          616.0,
          616.0,
          616.2,
          617.1
        ],
        "per_service_mem_mib": {
          "db": [
            132.7,
            132.8,
            132.9,
            132.9,
            132.7,
            132.6,
            132.7,
            132.6,
            132.6,
            132.6,
            132.6,
            132.6,
            132.5,
            132.6,
            132.6,
            132.7
          ],
          "redis": [
            9.0,
            8.9,
            9.0,
            8.9,
            8.9,
            9.0,
            9.1,
            8.9,
            9.0,
            9.0,
            9.0,
            9.1,
            9.0,
            8.9,
            9.1,
            8.9
          ],
          "seafile": [
            470.9,
            470.8,
            470.8,
            470.9,
            472.9,
            471.6,
            471.6,
            472.1,
            472.1,
            472.2,
            472.2,
            473.9,
            474.5,
            474.5,
            474.5,
            475.5
          ]
        }
      },
      "load": {
        "per_service": {
          "db": {
            "samples": 4,
            "mem_mean_mib": 133.93,
            "mem_max_mib": 134.1,
            "cpu_mean_pct": 9.77,
            "cpu_max_pct": 35.8
          },
          "redis": {
            "samples": 4,
            "mem_mean_mib": 8.99,
            "mem_max_mib": 9.02,
            "cpu_mean_pct": 0.86,
            "cpu_max_pct": 2.14
          },
          "seafile": {
            "samples": 4,
            "mem_mean_mib": 721.88,
            "mem_max_mib": 761.5,
            "cpu_mean_pct": 37.85,
            "cpu_max_pct": 95.48
          }
        },
        "total": {
          "samples": 4,
          "dropped_for_total": 0,
          "mem_mean_mib": 864.79,
          "mem_max_mib": 904.61,
          "cpu_mean_pct": 48.49,
          "cpu_max_pct": 132.49
        },
        "description": "The same load as the Nextcloud and ownCloud tests, through Seafile's own Web API. One user (the admin), over plain HTTP on the Compose network, one request at a time, each on a new connection. A Python script generates the same 103 random files (100 small ones of 1 KB to 1 MB, about 50 MB together, and three of 50 MB; same seed, same names, same order), creates a folder in the library, asks for one upload address for that folder (GET upload-link) and uploads the files to it with one multipart POST each, lists the folder with one GET of the directory, and downloads five files (three small, two large; one request for the download address and one for the file each) and checks their SHA-256. About 200 MB in total. The web API is used instead of WebDAV because it is what Seafile's web interface, mobile apps and scripts use; WebDAV is a separate, optional component that is off by default in Seafile 13. No browser, no sync client (Seafile's desktop client uses its own block-based sync protocol, which is not exercised), no chunked upload, no thumbnails, no sharing.",
        "duration_s": 4.0,
        "window": "from LAB_MARK load_start (or step start) until 2 s after the step ended",
        "reported_by_script": {
          "api": "seafile web api (api2) and the upload-api/files addresses it returns",
          "files_uploaded": 103,
          "small_files": 100,
          "large_files": 3,
          "bytes_uploaded": 194456599,
          "upload_seconds": 1.4,
          "listing_entries": 103,
          "listing_seconds": 0.01,
          "files_downloaded": 5,
          "bytes_downloaded": 101451451,
          "download_seconds": 1.0,
          "downloads_sha256_match": true,
          "requests": {
            "create_folder": {
              "sent": 1,
              "ok": 1,
              "statuses": {
                "201": 1
              }
            },
            "upload_link": {
              "sent": 1,
              "ok": 1,
              "statuses": {
                "200": 1
              }
            },
            "upload": {
              "sent": 103,
              "ok": 103,
              "statuses": {
                "200": 103
              }
            },
            "list": {
              "sent": 1,
              "ok": 1,
              "statuses": {
                "200": 1
              }
            },
            "download_link": {
              "sent": 5,
              "ok": 5,
              "statuses": {
                "200": 5
              }
            },
            "download": {
              "sent": 5,
              "ok": 5,
              "statuses": {
                "200": 5
              }
            }
          },
          "requests_total": 116,
          "requests_failed": 0
        },
        "output_tail": [
          "generated 103 files (100 small, 3 large), 194.5 MB",
          "uploaded 103 of 103 files, 194.5 MB in 1.4s; statuses {'200': 103}",
          "GET dir HTTP 200: 103 files in 0.01s; names and sizes match the upload: True",
          "downloaded 5 of 5 files, 101.5 MB in 1.0s"
        ],
        "series": [
          {
            "t_offset_s": 0.0,
            "total_mem_mib": 750.0,
            "total_cpu_pct": 132.49
          },
          {
            "t_offset_s": 2.0,
            "total_mem_mib": 902.24,
            "total_cpu_pct": 59.82
          },
          {
            "t_offset_s": 4.0,
            "total_mem_mib": 902.32,
            "total_cpu_pct": 0.23
          },
          {
            "t_offset_s": 6.0,
            "total_mem_mib": 904.61,
            "total_cpu_pct": 1.41
          }
        ],
        "series_start_offset_s": 1.4,
        "peak_note": "peak = highest value seen across docker stats samples (about one every 2-3 s); shorter spikes between samples are not seen"
      },
      "container_end_state": {
        "db": {
          "restart_count": 0,
          "oom_killed": false
        },
        "redis": {
          "restart_count": 0,
          "oom_killed": false
        },
        "seafile": {
          "restart_count": 0,
          "oom_killed": false
        }
      },
      "teardown": {
        "done": true,
        "volumes_removed": true,
        "images_removed": false,
        "error": null
      },
      "warnings": [],
      "finished_at": "2026-10-16T03:26:42Z",
      "elapsed_seconds": 185.1
    },
    {
      "run": 3,
      "started_at": "2026-10-16T03:26:42Z",
      "host": {
        "label": "github-actions ubuntu-latest (2 vCPU, 8 GB)",
        "ci": {
          "runs_on": "ubuntu-latest",
          "runner_environment": "github-hosted",
          "runner_os": "Linux",
          "runner_arch": "X64",
          "image_os": "ubuntu24",
          "image_version": "20261012.334.1"
        },
        "cpu_model": "AMD EPYC 9V45 96-Core Processor",
        "cpu_model_note": null,
        "cores": 2,
        "mem_total_mib": 7938,
        "kernel": "6.17.0-1022-azure",
        "os": "Ubuntu 24.04.5 LTS",
        "arch": "x86_64",
        "oci_arch": "amd64",
        "docker_server_version": "28.0.4",
        "docker_client_version": "28.0.4",
        "compose_client_version": "2.38.2",
        "storage_driver": "overlay2",
        "containerd_image_store": false,
        "source": "docker info + throwaway container reading /proc/cpuinfo on the daemon host",
        "compose_note": "Compose runs on the client machine; Docker server fields are from the daemon host"
      },
      "date": "2026-10-16",
      "startup": {
        "seconds": 17.5,
        "ok": true,
        "checks": [
          {
            "type": "container",
            "ok": true,
            "ready_after_s": 17.5,
            "detail": "shb-seafile-seafile-1=running/healthy, shb-seafile-db-1=running/healthy, shb-seafile-redis-1=running/healthy"
          }
        ],
        "up_command_seconds": 5.9,
        "definition": "wall clock from starting `docker compose up -d` until every health check passed; checks poll every 0.5 s from a throwaway container on the compose network, so resolution is about +/- 1 s"
      },
      "versions": {
        "db": "10.11.19",
        "redis": "8.10.2",
        "seafile": "13.0.28"
      },
      "setup": [
        {
          "exit_code": 0,
          "duration_s": 1.0,
          "reported": {
            "seafile_version": "13.0.28",
            "library_name": "loadtest",
            "library_id": "99d5af8a-d148-4fcc-ab0b-3631ffa16896",
            "library_created": true,
            "upload_link_ok": true
          },
          "output_tail": [
            "GET /api2/ping/ -> HTTP 200 \"pong\"",
            "GET /api2/server-info/ -> HTTP 200 version 13.0.28",
            "POST /api2/auth-token/ -> HTTP 200",
            "POST /api2/repos/ -> HTTP 200",
            "GET upload-link -> HTTP 200"
          ],
          "description": "Log in to the Web API with the admin account (POST /api2/auth-token/), create the library the load step uploads into (POST /api2/repos/), check that it is listed and that an upload address can be requested. Reports the server version Seafile gives."
        }
      ],
      "idle": {
        "per_service": {
          "db": {
            "samples": 11,
            "mem_mean_mib": 132.49,
            "mem_max_mib": 132.6,
            "cpu_mean_pct": 0.25,
            "cpu_max_pct": 2.6
          },
          "redis": {
            "samples": 11,
            "mem_mean_mib": 9.08,
            "mem_max_mib": 9.21,
            "cpu_mean_pct": 0.57,
            "cpu_max_pct": 1.97
          },
          "seafile": {
            "samples": 11,
            "mem_mean_mib": 448.65,
            "mem_max_mib": 449.7,
            "cpu_mean_pct": 0.69,
            "cpu_max_pct": 3.22
          }
        },
        "total": {
          "samples": 11,
          "dropped_for_total": 0,
          "mem_mean_mib": 590.22,
          "mem_max_mib": 591.09,
          "cpu_mean_pct": 1.52,
          "cpu_max_pct": 5.26
        },
        "window_seconds": 30.2,
        "series": [
          {
            "t_offset_s": 0.0,
            "total_mem_mib": 589.88,
            "total_cpu_pct": 0.28
          },
          {
            "t_offset_s": 3.0,
            "total_mem_mib": 589.88,
            "total_cpu_pct": 0.31
          },
          {
            "t_offset_s": 6.0,
            "total_mem_mib": 590.41,
            "total_cpu_pct": 5.26
          },
          {
            "t_offset_s": 9.1,
            "total_mem_mib": 590.05,
            "total_cpu_pct": 0.24
          },
          {
            "t_offset_s": 12.1,
            "total_mem_mib": 590.21,
            "total_cpu_pct": 0.29
          },
          {
            "t_offset_s": 15.1,
            "total_mem_mib": 590.0,
            "total_cpu_pct": 3.99
          },
          {
            "t_offset_s": 18.1,
            "total_mem_mib": 590.38,
            "total_cpu_pct": 0.27
          },
          {
            "t_offset_s": 21.1,
            "total_mem_mib": 590.52,
            "total_cpu_pct": 2.2
          },
          {
            "t_offset_s": 24.2,
            "total_mem_mib": 589.88,
            "total_cpu_pct": 1.44
          },
          {
            "t_offset_s": 27.2,
            "total_mem_mib": 590.12,
            "total_cpu_pct": 0.27
          },
          {
            "t_offset_s": 30.2,
            "total_mem_mib": 591.09,
            "total_cpu_pct": 2.12
          }
        ]
      },
      "settle": {
        "settled": true,
        "mode": "detected",
        "settle_seconds_used": 121.8,
        "settle_started_after_healthy_s": 2.5,
        "params": {
          "window_seconds": 60,
          "threshold_pct": 2.0,
          "threshold_min_mib": 10.0,
          "min_seconds": 120,
          "max_seconds": 600
        },
        "last_window": {
          "n": 21,
          "mean_mib": 589.79,
          "min_mib": 589.1,
          "max_mib": 590.33,
          "spread_mib": 1.23,
          "threshold_mib": 11.8
        },
        "rechecks": 0,
        "rule": "settled = over the last window_seconds the stack total varied (max - min) by less than max(threshold_pct of the window mean, threshold_min_mib); not before min_seconds, at the latest max_seconds, both counted from the end of the setup steps; the idle window must also be flat and agree with it. If max_seconds passes without settling, settled=false and the idle window is measured anyway."
      },
      "startup_peak": {
        "per_service_mem_mib": {
          "db": 133.0,
          "redis": 9.23,
          "seafile": 448.6
        },
        "total_mem_mib": 590.33,
        "samples": 42,
        "note": "highest value across docker stats samples (about one every 2-3 s) from healthy until the stack settled; shorter spikes between samples are not seen"
      },
      "timeline": {
        "step_s": 10,
        "t0": "healthy",
        "offsets_s": [
          10,
          20,
          30,
          40,
          50,
          60,
          70,
          80,
          90,
          100,
          110,
          120,
          130,
          140,
          150,
          160
        ],
        "total_mem_mib": [
          567.5,
          588.5,
          588.7,
          589.1,
          589.1,
          589.3,
          589.2,
          589.7,
          590.0,
          589.9,
          589.7,
          589.8,
          589.9,
          590.2,
          590.3,
          590.6
        ],
        "per_service_mem_mib": {
          "db": [
            132.7,
            132.8,
            132.6,
            132.9,
            132.8,
            132.6,
            132.5,
            132.6,
            132.5,
            132.5,
            132.4,
            132.5,
            132.4,
            132.6,
            132.5,
            132.4
          ],
          "redis": [
            9.0,
            8.9,
            8.9,
            9.0,
            9.0,
            9.0,
            9.0,
            9.0,
            9.2,
            9.1,
            9.0,
            8.9,
            8.9,
            9.1,
            9.1,
            9.1
          ],
          "seafile": [
            425.8,
            446.9,
            447.2,
            447.2,
            447.4,
            447.7,
            447.7,
            448.1,
            448.4,
            448.3,
            448.3,
            448.4,
            448.5,
            448.5,
            448.6,
            449.1
          ]
        }
      },
      "load": {
        "per_service": {
          "db": {
            "samples": 4,
            "mem_mean_mib": 133.57,
            "mem_max_mib": 133.8,
            "cpu_mean_pct": 3.09,
            "cpu_max_pct": 10.93
          },
          "redis": {
            "samples": 4,
            "mem_mean_mib": 8.98,
            "mem_max_mib": 9.01,
            "cpu_mean_pct": 0.26,
            "cpu_max_pct": 0.51
          },
          "seafile": {
            "samples": 4,
            "mem_mean_mib": 730.05,
            "mem_max_mib": 733.7,
            "cpu_mean_pct": 38.15,
            "cpu_max_pct": 104.39
          }
        },
        "total": {
          "samples": 4,
          "dropped_for_total": 0,
          "mem_mean_mib": 872.6,
          "mem_max_mib": 876.15,
          "cpu_mean_pct": 41.49,
          "cpu_max_pct": 115.83
        },
        "description": "The same load as the Nextcloud and ownCloud tests, through Seafile's own Web API. One user (the admin), over plain HTTP on the Compose network, one request at a time, each on a new connection. A Python script generates the same 103 random files (100 small ones of 1 KB to 1 MB, about 50 MB together, and three of 50 MB; same seed, same names, same order), creates a folder in the library, asks for one upload address for that folder (GET upload-link) and uploads the files to it with one multipart POST each, lists the folder with one GET of the directory, and downloads five files (three small, two large; one request for the download address and one for the file each) and checks their SHA-256. About 200 MB in total. The web API is used instead of WebDAV because it is what Seafile's web interface, mobile apps and scripts use; WebDAV is a separate, optional component that is off by default in Seafile 13. No browser, no sync client (Seafile's desktop client uses its own block-based sync protocol, which is not exercised), no chunked upload, no thumbnails, no sharing.",
        "duration_s": 3.9,
        "window": "from LAB_MARK load_start (or step start) until 2 s after the step ended",
        "reported_by_script": {
          "api": "seafile web api (api2) and the upload-api/files addresses it returns",
          "files_uploaded": 103,
          "small_files": 100,
          "large_files": 3,
          "bytes_uploaded": 194456599,
          "upload_seconds": 1.9,
          "listing_entries": 103,
          "listing_seconds": 0.02,
          "files_downloaded": 5,
          "bytes_downloaded": 101451451,
          "download_seconds": 0.5,
          "downloads_sha256_match": true,
          "requests": {
            "create_folder": {
              "sent": 1,
              "ok": 1,
              "statuses": {
                "201": 1
              }
            },
            "upload_link": {
              "sent": 1,
              "ok": 1,
              "statuses": {
                "200": 1
              }
            },
            "upload": {
              "sent": 103,
              "ok": 103,
              "statuses": {
                "200": 103
              }
            },
            "list": {
              "sent": 1,
              "ok": 1,
              "statuses": {
                "200": 1
              }
            },
            "download_link": {
              "sent": 5,
              "ok": 5,
              "statuses": {
                "200": 5
              }
            },
            "download": {
              "sent": 5,
              "ok": 5,
              "statuses": {
                "200": 5
              }
            }
          },
          "requests_total": 116,
          "requests_failed": 0
        },
        "output_tail": [
          "generated 103 files (100 small, 3 large), 194.5 MB",
          "uploaded 103 of 103 files, 194.5 MB in 1.9s; statuses {'200': 103}",
          "GET dir HTTP 200: 103 files in 0.02s; names and sizes match the upload: True",
          "downloaded 5 of 5 files, 101.5 MB in 0.5s"
        ],
        "series": [
          {
            "t_offset_s": 0.0,
            "total_mem_mib": 862.7,
            "total_cpu_pct": 115.83
          },
          {
            "t_offset_s": 2.0,
            "total_mem_mib": 875.61,
            "total_cpu_pct": 46.43
          },
          {
            "t_offset_s": 4.0,
            "total_mem_mib": 875.95,
            "total_cpu_pct": 3.44
          },
          {
            "t_offset_s": 6.0,
            "total_mem_mib": 876.15,
            "total_cpu_pct": 0.28
          }
        ],
        "series_start_offset_s": 1.4,
        "peak_note": "peak = highest value seen across docker stats samples (about one every 2-3 s); shorter spikes between samples are not seen"
      },
      "container_end_state": {
        "db": {
          "restart_count": 0,
          "oom_killed": false
        },
        "redis": {
          "restart_count": 0,
          "oom_killed": false
        },
        "seafile": {
          "restart_count": 0,
          "oom_killed": false
        }
      },
      "teardown": {
        "done": true,
        "volumes_removed": true,
        "images_removed": false,
        "error": null
      },
      "warnings": [],
      "finished_at": "2026-10-16T03:29:46Z",
      "elapsed_seconds": 183.5
    }
  ],
  "load_defined": true,
  "notes": [
    "Host: a GitHub Actions runner (ubuntu-latest, x86_64, 2 vCPU, 8 GB RAM; the CPU model varies between runners and each run records its own). Numbers are valid for that host only.",
    "Image: seafileltd/seafile-mc:13.0.28, Seafile Community Edition 13.0.28 (18 Sep 2026), the newest release Seafile's own changelog (plus.seafile.com/wiki/publish/seafile-wiki/5L80/) does not label beta. 14.0.9 (14 Oct 2026) is labelled beta there and is not tested. The image's version label says 24.04 (the Ubuntu base), so the version is read from the running server (GET /api2/server-info/).",
    "Companions (Seafile 13 official Docker file): MariaDB 10.11 and Redis, in their own containers. Memcached is optional since 13 and not used. Caddy (reverse proxy), SeaDoc (online documents), the notification server, the metadata server, Seafile AI, the thumbnail server and WebDAV are not run. The container count is three, against four for Nextcloud (app, cron, PostgreSQL, Redis) and one for ownCloud Infinite Scale.",
    "Measured: idle RAM and CPU after the first start with the admin account and one empty library; RAM and CPU while the load of load.description runs (a few seconds); image sizes; start-up time. Not measured: the desktop or mobile sync clients, external storage or S3 backends, online editing (SeaDoc, OnlyOffice, Collabora), full-text search, previews, LDAP/SSO, many users, long-term growth.",
    "Equivalence with the Nextcloud test: same 103 files (same generator and seed), same order, one request at a time, one user, plain HTTP, 5 downloads with a SHA-256 check. Differences that come from the products: Seafile needs one request for an upload address (reused for every file) and one per download address; Nextcloud's PROPFIND also returns the folder itself, Seafile's listing returns files only, so `listing_entries` is 103 for both. The Nextcloud result calls the listing `propfind_entries` and `propfind_seconds`.",
    "The load script reports every request kind with the HTTP statuses it got (`requests` in the load result); any failed request fails the run."
  ],
  "warnings": [],
  "files": {
    "compose": "seafile.compose.yaml",
    "env": "seafile.env"
  },
  "definitions": {
    "memory": "cgroup working set as reported by `docker stats` (usage minus inactive file cache), MiB = 2^20 bytes",
    "cpu": "percent of ONE core as reported by `docker stats` (4 busy cores = 400)",
    "total": "stats over the sum of all containers at the same instant",
    "sample_interval": "docker stats --no-stream takes about 1-2 s per call, so samples are 2-3 s apart",
    "runs": "each run is a full fresh cycle (up, health, setup, settle, idle, load, down -v); the published figure is the median over the runs, shown with the min-max range; see summary.rule"
  }
}
