diff --git a/modules/services/web/rails/default.nix b/modules/services/web/rails/default.nix index 4886ea6..1bed7de 100644 --- a/modules/services/web/rails/default.nix +++ b/modules/services/web/rails/default.nix @@ -16,6 +16,7 @@ let # The main Rails service: mainService = app: { name = "main"; + schedule = null; isMain = true; script = '' @@ -98,10 +99,11 @@ let description = "${app.name} (Ruby on Rails) ${service.name}"; path = appPath app; environment = appEnv app; - wantedBy = [ "multi-user.target" ]; + + # Only start this service if it isn't scheduled by a timer. + wantedBy = optional (service.schedule == null) "multi-user.target"; wants = - optional (!service.isMain) "rails-${app.name}-main" ++ plib.keyService app.database.passwordFile ++ plib.keyService app.sourcedFile; @@ -166,6 +168,17 @@ let }; }; + ############################################################################## + # Schedule some services with a systemd timer: + appTimer = app: service: optionalAttrs (service.schedule != null) { + "rails-${app.name}-${service.name}" = { + description = "${app.name} (Ruby on Rails) ${service.name}"; + wantedBy = [ "timers.target" ]; + timerConfig.OnCalendar = service.schedule; + timerConfig.Unit = "rails-${app.name}-${service.name}.service"; + }; + }; + ############################################################################## # Collect all services for a given application and turn them into # systemd services. @@ -173,6 +186,12 @@ let foldr (service: set: recursiveUpdate set (appService app service)) {} ( [(mainService app)] ++ attrValues app.services ); + ############################################################################## + # Collect all services and turn them into systemd timers: + appTimers = app: + foldr (service: set: recursiveUpdate set (appTimer app service)) {} + (attrValues app.services); + ############################################################################## # Generate a user account for a Ruby on Rails application: appUser = app: { @@ -217,6 +236,7 @@ in # Each application gets one or more systemd services to keep it # running. systemd.services = collectApps appServices; + systemd.timers = collectApps appTimers; # Rotate all of the log files: services.logrotate = { diff --git a/modules/services/web/rails/options.nix b/modules/services/web/rails/options.nix index de83da6..cc78815 100644 --- a/modules/services/web/rails/options.nix +++ b/modules/services/web/rails/options.nix @@ -68,6 +68,18 @@ let description = "Shell commands executed as the service's main process."; }; + schedule = mkOption { + type = types.nullOr types.str; + default = null; + example = "*-*-* *:00/5:00"; + description = '' + If null (the default), run this service in the background + continuously, restarting it if it stops. However, if this + option is set, it should be a systemd calendar string and + this service will run on a scheduled timer instead. + ''; + }; + isMain = mkOption { internal = true; type = types.bool;