How to Schedule a .NET Importer with systemd Timers
A useful local importer should not depend on someone remembering to open a terminal. On a Linux host, systemd can run it under a dedicated account, retain its journal output and schedule later executions. The application owns its import rules and transaction boundary, while systemd owns when and under which operating-system identity it runs.
We will deploy the ObjectSpace importer from the preceding article as a one-shot service. It opens its persistent archive, imports the fixture, commits and exits. A timer starts later runs. This keeps the example's file-store lifetime synchronous rather than moving a loaded ObjectSpace between asynchronous worker threads.
Contents
Publish the NuGet-Based Application
The downloadable project uses Sphere10.Framework 3.1.3. Install the .NET 10 SDK on the build machine and a compatible runtime on the target host. Publish for the target host's architecture. The linux-x64 runtime identifier below is an example for an x64 Linux host.
dotnet restore Example.csproj
dotnet publish Example.csproj -c Release -r linux-x64 --self-contained false -o ./publish
Copy the resulting publish directory to the application's chosen installation folder. The service below expects /opt/sphere10-archive/Example.dll and uses /var/lib/sphere10-archive for its mutable data. Keep installation files and stored documents separate so replacing application binaries does not replace the archive.
Create a Dedicated Service Identity
The account needs read access to its installed program and write access to its own archive folder. It does not need to run as root. Adapt these commands to an existing account policy instead of replacing another service's ownership.
sudo useradd --system --home /var/lib/sphere10-archive --shell /usr/sbin/nologin sphere10-archive
sudo install -d -o sphere10-archive -g sphere10-archive /var/lib/sphere10-archive
Define the One-Shot Service
Save this unit as /etc/systemd/system/sphere10-archive.service. Confirm the dotnet executable path on the target host by running command -v dotnet. This example uses /usr/bin/dotnet.
[Unit]
Description=Sphere 10 archive import
[Service]
Type=oneshot
User=sphere10-archive
Group=sphere10-archive
WorkingDirectory=/var/lib/sphere10-archive
ExecStart=/usr/bin/dotnet /opt/sphere10-archive/Example.dll /var/lib/sphere10-archive
Type=oneshot means systemd waits for the importer process to finish. The application commits its batch explicitly and lets failures produce a failed service result. Do not conceal an exception with an unconditional success exit merely to make the unit appear healthy.
Add a Timer
Save the companion timer as /etc/systemd/system/sphere10-archive.timer. The calendar expression runs every fifteen minutes. Persistent=true concerns missed calendar activations and does not provide database recovery.
[Unit]
Description=Schedule the Sphere 10 archive import
[Timer]
OnCalendar=*:0/15
Persistent=true
Unit=sphere10-archive.service
[Install]
WantedBy=timers.target
sudo systemd-analyze verify /etc/systemd/system/sphere10-archive.service /etc/systemd/system/sphere10-archive.timer
sudo systemctl daemon-reload
sudo systemctl start sphere10-archive.service
sudo journalctl -u sphere10-archive.service -n 30 --no-pager
sudo systemctl enable --now sphere10-archive.timer
Check the Application Result
A fresh archive reports two inserted revisions. A later run against the same input reports zero newly inserted revisions and two stored revisions. The importer explicitly skips revisions already present. The scheduler does not make arbitrary application actions idempotent.
Avoid launching an independent second importer against the same store. A systemd timer does not create a queue of overlapping instances of the same active service, but that does not prevent someone starting another process manually. Back up the archive according to the application's consistency requirements, and preserve its compatible schema and configuration when upgrading.
See the existing systemd operations guide , the official service unit reference and timer reference . This arrangement makes the Framework useful in a small unattended data tool while keeping application persistence, scheduling and operating-system ownership understandable.
Continue the Series
How to Turn a Notion Export into a Searchable C# Object Store
How to Give Your C# Objects Commit and Rollback
For the broader Sphere 10 development toolkit, see the Sphere10 Framework overview .