s3syncy
Cross-platform, multithreaded S3 file synchronisation daemon.
Features
- Continuous sync — watches directories for changes in real-time (via
watchdog) and runs periodic full scans as a safety net. - Daemon controls — start in background and control with
stop,pause,resume,reload,daemon-status. - Multithreaded — configurable thread pool for parallel uploads/downloads.
- Bandwidth throttling — token-bucket rate limiter (upload & download independently).
- Resource-friendly — chunked streaming (no full-file buffering), optional soft memory cap, bounded thread pool.
- Configurable — single
config.yamlcontrols everything (S3 target, threads, bandwidth, conflict strategy, integrity, logging). - Gitignore-style exclusions —
.syncignorefile uses the same pattern syntax as.gitignore. - Auto-reload — config and exclusion files are reloaded automatically on change.
- Searchable local index — SQLite metadata database with full-text search on file paths and folder-prefix listing.
- Conflict resolution —
local_wins,remote_wins,newest_wins, orskip— with optional.bakbackup before overwriting. - Remote delete self-heal — if an object is deleted directly from S3 but still exists locally, daemon restores it on the next scan.
- Integrity checks — post-upload hash verification (MD5 via S3 ETag, or SHA256). Configurable reaction:
warn,retry, ordelete_remote. - Cross-platform — macOS, Linux, Windows (Python 3.10+).
Quick Start
# Install from PyPI
pip install s3syncy
# Initialize configuration
s3syncy init
# Edit config.yaml with your S3 bucket and sync directories
# Then run:
s3syncy start -c config.yaml --background
# Check status
s3syncy status -c config.yaml
CLI Commands
| Command | Description |
|---|---|
s3syncy start -c config.yaml |
Start the sync daemon |
s3syncy start -c config.yaml --background |
Start daemon in background |
s3syncy stop -c config.yaml |
Stop background daemon |
s3syncy pause -c config.yaml |
Pause syncing (daemon stays alive) |
s3syncy resume -c config.yaml |
Resume syncing after pause |
s3syncy reload -c config.yaml |
Reload config + exclusions immediately |
s3syncy daemon-status -c config.yaml |
Show daemon PID/running/state info |
s3syncy search "report" -c config.yaml |
Search the index for files matching "report" |
s3syncy ls "photos/2024" -c config.yaml |
List synced files under a path prefix |
s3syncy pull "docs/file.pdf" ./local.pdf -c config.yaml |
Download a single file from S3 |
s3syncy status -c config.yaml |
Show index statistics (total files, synced count, total size) |
s3syncy init |
Create starter config.yaml and .syncignore |
Configuration
See config.yaml for full documentation. Key settings:
sync_dirs:
- ~/Documents/sync
- ~/Desktop/uploads
s3:
bucket: "my-bucket"
prefix: "backups"
region: "us-east-1"
threads: 4
scan_interval_seconds: 300
bandwidth:
upload_limit_mbps: 10 # 0 = unlimited
download_limit_mbps: 0
conflict:
strategy: "newest_wins" # local_wins | remote_wins | newest_wins | skip
backup_before_overwrite: true
integrity:
enabled: true
algorithm: "md5" # md5 | sha256
on_failure: "warn" # warn | retry | delete_remote
When multiple sync_dirs are configured, one daemon handles all of them.
S3 keys are namespaced per root (for example Documents/file.txt, uploads-2/file.txt) to avoid collisions.
.syncignore
Works exactly like .gitignore:
# OS junk
.DS_Store
Thumbs.db
# Build artefacts
node_modules/
__pycache__/
*.pyc
# Secrets
.env
*.pem
Signals (Unix)
SIGINT/SIGTERM— graceful shutdown (finish in-flight transfers, close index).SIGHUP— reload config and exclusions.SIGUSR1— pause syncing.SIGUSR2— resume syncing.
Architecture
┌─────────────┐ events ┌─────────────┐ ThreadPool ┌──────────┐
│ watchdog │ ──────────────▸ │ watcher │ ──────────────▸ │ engine │
│ (OS-level) │ debounced │ (handler) │ submit tasks │ (upload/ │
└─────────────┘ └──────┬──────┘ │ download)│
│ └────┬─────┘
periodic │ │
full scan ▼ ▼
┌─────────────┐ ┌──────────────┐
│ daemon │ │ S3 (boto3) │
│ (main loop) │ │ + throttle │
└─────────────┘ │ + integrity │
│ └──────────────┘
▼
┌─────────────┐
│ SQLite │
│ index │
└─────────────┘
Development
Setup Development Environment
# Clone the repository
git clone https://github.com/mtahle/s3syncy.git
cd s3syncy
# Install in development mode
pip install -e .
# Install development dependencies
pip install -r requirements-dev.txt
Running Tests
# Run all tests
pytest
# Run with coverage
pytest --cov=s3syncy --cov-report=html
# Run only unit tests
pytest tests/unit -m unit
# Run specific test file
pytest tests/unit/test_config.py
Code Quality
# Format code
black s3syncy tests
# Sort imports
isort s3syncy tests
# Type checking
mypy s3syncy
# Linting
ruff check s3syncy tests
License
MIT
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
s3syncy-1.1.0.tar.gz
(40.5 kB
view details)
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
s3syncy-1.1.0-py3-none-any.whl
(26.8 kB
view details)
File details
Details for the file s3syncy-1.1.0.tar.gz.
File metadata
- Download URL: s3syncy-1.1.0.tar.gz
- Upload date:
- Size: 40.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e89ce50185aadea17c4934253a7fa6e19c3f778c19d13ef44ad3f99a9b5a04a2
|
|
| MD5 |
633cac36fa0921c8c0ca1af0710d693c
|
|
| BLAKE2b-256 |
38649d7ca67e01e2752b41f0d4de70b85001a549c7dea8ea67418611a58c6c98
|
File details
Details for the file s3syncy-1.1.0-py3-none-any.whl.
File metadata
- Download URL: s3syncy-1.1.0-py3-none-any.whl
- Upload date:
- Size: 26.8 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/7.0.0 CPython/3.13.14
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
112d34a2372cb0b5f84b3a89297664bf13d1213381d1e28516338f0dc05f76ce
|
|
| MD5 |
74b0f5f9ed81bdeda7590625525b6813
|
|
| BLAKE2b-256 |
eaf8bf8d09e935a77624b857620ac0cb3066d2a7e5597179c93cbdfade5e3816
|