Skip to main content

Scheduling a Task

Tasks are scheduled in the Django admin panel under Django Q and Scheduled Tasks. Add a new task, give the task a name, select one of the server-approved functions, and configure its schedule. Tasks can run once or repeatedly (e.g. minutes, hourly, daily, weekly). You can schedule them by time or using cron.
The function and hook lists are controlled by a server-side allowlist. An administrator who only has access to the admin panel cannot add Python functions or system commands to these lists.
You can provide approved arguments for functions that accept them. Ghostwriter rejects unknown arguments and values with the wrong type. For example, ghostwriter.shepherd.tasks.scan_servers accepts only_active=True to restrict scanning to servers that are in use.

Example Scheduled Task

Visit the Django Q database from the admin panel to access the Scheduled Tasks. For example, you may wish to create a scheduled task to automatically release domains at the end of a project. There is a task for this already in tasks.py, ghostwriter.shepherd.tasks.release_domains. It appears in the dropdown as Release Domains.

Available Task Arguments

Arguments may be supplied positionally in the Arguments field or by name in the Keyword arguments field. Both fields use Python literal syntax, so string values must be quoted. For example, enter 'nightly-backup' in Arguments or command_name='nightly-backup' in Keyword arguments. Do not provide the same parameter in both fields.

Configuring the Server Allowlist

Ghostwriter includes its prebuilt scheduled tasks in the default policy. Server operators can replace or extend GHOSTWRITER_DJANGO_Q_SCHEDULE_TASKS from a settings fragment such as settings/10-django-q-policy.py. The Ghostwriter CLI mounts the settings directory read-only into the web and queue containers.
Task entries use exact dotted callable paths. Prefixes and wildcards are not supported. Argument policies support bool, float, int, and str values, along with name, required, required_parameters, nullable, choices, min, and max restrictions. A named positional argument can also appear in kwargs, allowing administrators to use either input style. Set allow_any_arguments only for a trusted function that performs its own strict input validation. Result hooks use the separate GHOSTWRITER_DJANGO_Q_SCHEDULE_HOOKS mapping. Ghostwriter exposes its built-in ghostwriter.modules.notifications_slack.send_slack_complete_msg hook by default. Generic execution functions such as os.system, subprocess.run, and django.core.management.call_command should never be allowlisted.

Fixed System Commands

Server operators can expose a fixed command by adding it to GHOSTWRITER_DJANGO_Q_COMMANDS:
The executable path and all arguments are fixed in the server configuration. Commands run without a shell and with only the explicitly configured environment. The admin panel permits selecting the command name but does not permit editing the executable, arguments, working directory, or environment. Restart both the Ghostwriter web and queue services after changing the policy. Changes are intentionally not loaded from the database or admin panel.

Auditing Existing Schedules

The task allowlist is deployment-specific, so Ghostwriter does not use a Django data migration to modify existing schedules. Instead, use the policy audit command as an operational migration when upgrading or enabling a more restrictive policy. For the safest rollout:
  1. Stop the Django Q cluster so an old scheduler or worker cannot execute tasks during the upgrade.
  2. Deploy the new Ghostwriter code and the intended server-side allowlist.
  3. Audit the existing schedules:
  1. Add any legitimate custom tasks reported by the audit to the server-side allowlist, or pause every schedule that does not satisfy the current policy:
  1. Restart the Ghostwriter web and Django Q services.
Disallowed schedules are paused by setting repeats=0; they are not deleted. This preserves their configuration for later review. If a disallowed schedule is missed by the audit, the restricted scheduler pauses it when it becomes due. A task already present in the queue is checked again by the worker and recorded as a failed task without importing or executing the denied function. Historical successful and failed task records remain available, but the admin panel cannot resubmit them unless they satisfy the current policy.
The allowlist limits administrators who only control the application or Django admin panel. Anyone who can modify the server configuration, application code, queue, database, or application secrets is already inside the server trust boundary.