filed

Job queue using FUSE

git clone git://mccd.space/filed

commit f8047bf8e3a8fd9899a89cfeb4e319ce5ab5dde0
parent f6476d60af5d20a453d8c18e794e0e870225b733
Author: Marc Coquand <marc@coquand.email>
Date:   Sun, 14 Dec 2025 19:45:52 +0100

docs and add config

Diffstat:
Mqj.1.scd | 48+++++++++++++++++++++++++++++++++++++-----------
Mstore/config.go | 10++++++----
Mstore/store.go | 3++-
3 files changed, 45 insertions(+), 16 deletions(-)
diff --git a/qj.1.scd b/qj.1.scd
@@ -1,33 +1,59 @@
-qj(1)
+QJ(1)
 
 # NAME
 
-qj - Simple job queue
+qj - queue jobs utility
 
 # SYNOPSIS
 
-*qj* _MOUNTPOINT_ _DBPATH_
+*qj* _mountpoint_ _dbpath_
 
 # DESCRIPTION
 
-qj is a simple job queue that operates using files by setting up a virtual
-file system on _MOUNTPOINT_.
+qj is a job queue that operates on files mounted to _mountpoint_.
 
-qj exposes 4 directories: *pending*, *active*, *failed*, *completed*. Files
+qj exposes 4 directories, where each directory contains zero or more _jobs_. 
+Job names must be unique across all four directories. The directories are
+
+	*pending* - jobs to be run. To create a new job, create a file 
+	here with the command to run.
+
+	*active* - currently running jobs. You can change the max amount of
+	allowed concurrent jobs in settings. Directory is read-only.
+
+	*failed* - jobs that exceeded retry count. You can retry a job by
+	moving them back to pending. You can also safely remove jobs here.
+
+	*completed* - jobs that succeeded, with content being the job
+	output. Jobs can safely be removed, and you might want to use _CRON(8)_
+	to delete older jobs regularly.
+
+*pending*, *active*, *failed*, *completed*. Files
 in the directories correspond to jobs. To create a job, simply add it to
 *pending*. Each job name must be unique globally across all four directories. 
 
-qj exposes 3 files: 
+qj exposes 2 files: 
+
+	*new-id* generate a unique id that can be used for job names
 
-	_new-id_ generate a unique id that can be used for job names
-	_config.json_ provides various settings such as max-jobs, timeouts. 
+	*config.json* provides settings for max-retries, timeouts, max
+	concurrent jobs.
+
+# SECURITY CONSIDERATIONS
+
+qj uses unix file permissions to manage access. 
 
 # EXAMPLES
 
-Create a new job with $JOBID that calculates 1+1:
+Create a new job with $JOBID that echoes hello world:
 
 	$ JOBID="$(cat /var/qj/new-id)"
-	$ printf "echo hello-world" >> "/var/qj/pending/$JOBID"
+
+	$ printf "echo helloworld" >> "/var/qj/pending/$JOBID"
+
+Retry a failing job:
+
+	$ mv /var/qj/failed/E6Xe /var/qj/pending
 
 Periodic jobs can be set up using _CRON(8)_.
 
diff --git a/store/config.go b/store/config.go
@@ -3,21 +3,23 @@ package store
 type Config struct {
 	MaxAttempts int `json:"max_attempts"`
 	TimeoutSec  int `json:"timeout_sec"`
+	// Max amount of concurrent jobs
+	MaxJobCount int `json:"max_job_count"`
 }
 
 func (st *Store) UpdateConfig(conf Config) error {
 	query := `
 		UPDATE config
-		SET max_attempts = ?, timeout_sec = ?
+		SET max_attempts = ?, timeout_sec = ?, max_job_count = ?
 		WHERE id = 0
 		`
-	_, err := st.db.Exec(query, conf.MaxAttempts, conf.TimeoutSec)
+	_, err := st.db.Exec(query, conf.MaxAttempts, conf.TimeoutSec, conf.MaxJobCount)
 	return err
 }
 
 func (st *Store) GetConfig() (conf Config) {
-	query := `SELECT max_attempts, timeout_sec FROM config WHERE id = 0`
-	err := st.db.QueryRow(query).Scan(&conf.MaxAttempts, &conf.TimeoutSec)
+	query := `SELECT max_attempts, timeout_sec, max_job_count FROM config WHERE id = 0`
+	err := st.db.QueryRow(query).Scan(&conf.MaxAttempts, &conf.TimeoutSec, &conf.MaxJobCount)
 	if err != nil {
 		panic(err)
 	}
diff --git a/store/store.go b/store/store.go
@@ -68,7 +68,8 @@ func (s *Store) initSchema() error {
 	CREATE TABLE IF NOT EXISTS config (
 		id INTEGER PRIMARY KEY CHECK (id = 0),
 		max_attempts INTEGER DEFAULT 3,
-		timeout_sec INTEGER DEFAULT 180
+		timeout_sec INTEGER DEFAULT 180,
+		max_job_count INTEGER DEFAULT 20
 	);
 	INSERT INTO config (id) VALUES (0) ON CONFLICT DO NOTHING;
 	CREATE TRIGGER IF NOT EXISTS auto_increment_inode_trigger