mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-31 21:06:25 -06:00
Allow plugins to register system jobs
This commit is contained in:
parent
39e5c0d24c
commit
d7b03ee47e
@ -31,12 +31,20 @@ You can schedule the background job from within your code (e.g. from a model's `
|
|||||||
|
|
||||||
### Attributes
|
### Attributes
|
||||||
|
|
||||||
`JobRunner` attributes are defined under a class named `Meta` within the job. These are optional, but encouraged.
|
`JobRunner` attributes are defined under a class named `Meta` within the job. These are optional (unless specified otherwise), but encouraged.
|
||||||
|
|
||||||
#### `name`
|
#### `name`
|
||||||
|
|
||||||
This is the human-friendly names of your background job. If omitted, the class name will be used.
|
This is the human-friendly names of your background job. If omitted, the class name will be used.
|
||||||
|
|
||||||
|
#### `enabled`
|
||||||
|
|
||||||
|
When the `JobRunner` is defined as [system job](#system-jobs), this attribute controls whether a job will be scheduled. By default, this attribute is `True`.
|
||||||
|
|
||||||
|
#### `interval` *(required for system jobs)*
|
||||||
|
|
||||||
|
When the `JobRunner` is defined as [system job](#system-jobs), this attribute controls the interval of the scheduled job.
|
||||||
|
|
||||||
### Scheduled Jobs
|
### Scheduled Jobs
|
||||||
|
|
||||||
As described above, jobs can be scheduled for immediate execution or at any later time using the `enqueue()` method. However, for management purposes, the `enqueue_once()` method allows a job to be scheduled exactly once avoiding duplicates. If a job is already scheduled for a particular instance, a second one won't be scheduled, respecting thread safety. An example use case would be to schedule a periodic task that is bound to an instance in general, but not to any event of that instance (such as updates). The parameters of the `enqueue_once()` method are identical to those of `enqueue()`.
|
As described above, jobs can be scheduled for immediate execution or at any later time using the `enqueue()` method. However, for management purposes, the `enqueue_once()` method allows a job to be scheduled exactly once avoiding duplicates. If a job is already scheduled for a particular instance, a second one won't be scheduled, respecting thread safety. An example use case would be to schedule a periodic task that is bound to an instance in general, but not to any event of that instance (such as updates). The parameters of the `enqueue_once()` method are identical to those of `enqueue()`.
|
||||||
@ -62,6 +70,33 @@ class MyModel(NetBoxModel):
|
|||||||
MyTestJob.enqueue(instance=self)
|
MyTestJob.enqueue(instance=self)
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### System Jobs
|
||||||
|
|
||||||
|
Some plugins may implement background jobs that are decoupled from any object and the request-response cycle. Typical use cases would be housekeeping tasks or synchronization jobs. These can be created using *system jobs*. The `JobRunner` class has everything included to provide this type of job as well. Just add the appropriate metadata to let NetBox schedule all background jobs automatically.
|
||||||
|
|
||||||
|
!!! info
|
||||||
|
All system jobs are automatically scheduled just before the `./manage.py rqworker` command is started and the job queue is processed. The schedules are also checked at each restart of this process.
|
||||||
|
|
||||||
|
#### Example
|
||||||
|
|
||||||
|
```python title="jobs.py"
|
||||||
|
from netbox.jobs import JobRunner
|
||||||
|
from .models import MyModel
|
||||||
|
|
||||||
|
class MyHousekeepingJob(JobRunner):
|
||||||
|
class Meta:
|
||||||
|
name = "My Housekeeping Job"
|
||||||
|
interval = 60 # every 60 minutes
|
||||||
|
|
||||||
|
def run(self, *args, **kwargs):
|
||||||
|
MyModel.objects.filter(foo='bar').delete()
|
||||||
|
|
||||||
|
system_jobs = (
|
||||||
|
MyHousekeepingJob,
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
## Task queues
|
## Task queues
|
||||||
|
|
||||||
Three task queues of differing priority are defined by default:
|
Three task queues of differing priority are defined by default:
|
||||||
|
@ -18,6 +18,6 @@ backends = [MyDataBackend]
|
|||||||
```
|
```
|
||||||
|
|
||||||
!!! tip
|
!!! tip
|
||||||
The path to the list of search indexes can be modified by setting `data_backends` in the PluginConfig instance.
|
The path to the list of data backends can be modified by setting `data_backends` in the PluginConfig instance.
|
||||||
|
|
||||||
::: netbox.data_backends.DataBackend
|
::: netbox.data_backends.DataBackend
|
||||||
|
@ -8,7 +8,7 @@ from packaging import version
|
|||||||
|
|
||||||
from netbox.registry import registry
|
from netbox.registry import registry
|
||||||
from netbox.search import register_search
|
from netbox.search import register_search
|
||||||
from netbox.utils import register_data_backend
|
from netbox.utils import register_data_backend, register_system_job
|
||||||
from .navigation import *
|
from .navigation import *
|
||||||
from .registration import *
|
from .registration import *
|
||||||
from .templates import *
|
from .templates import *
|
||||||
@ -26,6 +26,7 @@ registry['plugins'].update({
|
|||||||
DEFAULT_RESOURCE_PATHS = {
|
DEFAULT_RESOURCE_PATHS = {
|
||||||
'search_indexes': 'search.indexes',
|
'search_indexes': 'search.indexes',
|
||||||
'data_backends': 'data_backends.backends',
|
'data_backends': 'data_backends.backends',
|
||||||
|
'system_jobs': 'jobs.system_jobs',
|
||||||
'graphql_schema': 'graphql.schema',
|
'graphql_schema': 'graphql.schema',
|
||||||
'menu': 'navigation.menu',
|
'menu': 'navigation.menu',
|
||||||
'menu_items': 'navigation.menu_items',
|
'menu_items': 'navigation.menu_items',
|
||||||
@ -73,6 +74,7 @@ class PluginConfig(AppConfig):
|
|||||||
# Optional plugin resources
|
# Optional plugin resources
|
||||||
search_indexes = None
|
search_indexes = None
|
||||||
data_backends = None
|
data_backends = None
|
||||||
|
system_jobs = None
|
||||||
graphql_schema = None
|
graphql_schema = None
|
||||||
menu = None
|
menu = None
|
||||||
menu_items = None
|
menu_items = None
|
||||||
@ -111,6 +113,11 @@ class PluginConfig(AppConfig):
|
|||||||
for backend in data_backends:
|
for backend in data_backends:
|
||||||
register_data_backend()(backend)
|
register_data_backend()(backend)
|
||||||
|
|
||||||
|
# Register system jobs (if defined)
|
||||||
|
system_jobs = self._load_resource('system_jobs') or []
|
||||||
|
for job in system_jobs:
|
||||||
|
register_system_job()(job)
|
||||||
|
|
||||||
# Register template content (if defined)
|
# Register template content (if defined)
|
||||||
if template_extensions := self._load_resource('template_extensions'):
|
if template_extensions := self._load_resource('template_extensions'):
|
||||||
register_template_extensions(template_extensions)
|
register_template_extensions(template_extensions)
|
||||||
|
14
netbox/netbox/tests/dummy_plugin/jobs.py
Normal file
14
netbox/netbox/tests/dummy_plugin/jobs.py
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
from netbox.jobs import JobRunner
|
||||||
|
|
||||||
|
|
||||||
|
class DummySystemJob(JobRunner):
|
||||||
|
class Meta:
|
||||||
|
interval = 60
|
||||||
|
|
||||||
|
def run(self, *args, **kwargs):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
system_jobs = (
|
||||||
|
DummySystemJob,
|
||||||
|
)
|
@ -7,6 +7,7 @@ from django.urls import reverse
|
|||||||
|
|
||||||
from netbox.tests.dummy_plugin import config as dummy_config
|
from netbox.tests.dummy_plugin import config as dummy_config
|
||||||
from netbox.tests.dummy_plugin.data_backends import DummyBackend
|
from netbox.tests.dummy_plugin.data_backends import DummyBackend
|
||||||
|
from netbox.tests.dummy_plugin.jobs import DummySystemJob
|
||||||
from netbox.plugins.navigation import PluginMenu
|
from netbox.plugins.navigation import PluginMenu
|
||||||
from netbox.plugins.utils import get_plugin_config
|
from netbox.plugins.utils import get_plugin_config
|
||||||
from netbox.graphql.schema import Query
|
from netbox.graphql.schema import Query
|
||||||
@ -130,6 +131,13 @@ class PluginTest(TestCase):
|
|||||||
self.assertIn('dummy', registry['data_backends'])
|
self.assertIn('dummy', registry['data_backends'])
|
||||||
self.assertIs(registry['data_backends']['dummy'], DummyBackend)
|
self.assertIs(registry['data_backends']['dummy'], DummyBackend)
|
||||||
|
|
||||||
|
def test_system_jobs(self):
|
||||||
|
"""
|
||||||
|
Check registered system jobs.
|
||||||
|
"""
|
||||||
|
self.assertIn(DummySystemJob.name, registry['system_jobs'])
|
||||||
|
self.assertIs(registry['system_jobs'][DummySystemJob.name], DummySystemJob)
|
||||||
|
|
||||||
def test_queues(self):
|
def test_queues(self):
|
||||||
"""
|
"""
|
||||||
Check that plugin queues are registered with the accurate name.
|
Check that plugin queues are registered with the accurate name.
|
||||||
|
Loading…
Reference in New Issue
Block a user