save start and end directly in timestamp from default_timer()
Signed-off-by: Jens Langhammer <jens@goauthentik.io>
This commit is contained in:
parent
f64ce142e4
commit
4e44354680
|
@ -1,4 +1,5 @@
|
||||||
"""Tasks API"""
|
"""Tasks API"""
|
||||||
|
from datetime import datetime, timezone
|
||||||
from importlib import import_module
|
from importlib import import_module
|
||||||
|
|
||||||
from django.contrib import messages
|
from django.contrib import messages
|
||||||
|
@ -6,13 +7,7 @@ from django.utils.translation import gettext_lazy as _
|
||||||
from drf_spectacular.types import OpenApiTypes
|
from drf_spectacular.types import OpenApiTypes
|
||||||
from drf_spectacular.utils import OpenApiResponse, extend_schema
|
from drf_spectacular.utils import OpenApiResponse, extend_schema
|
||||||
from rest_framework.decorators import action
|
from rest_framework.decorators import action
|
||||||
from rest_framework.fields import (
|
from rest_framework.fields import CharField, ChoiceField, ListField, SerializerMethodField
|
||||||
CharField,
|
|
||||||
ChoiceField,
|
|
||||||
DateTimeField,
|
|
||||||
ListField,
|
|
||||||
SerializerMethodField,
|
|
||||||
)
|
|
||||||
from rest_framework.request import Request
|
from rest_framework.request import Request
|
||||||
from rest_framework.response import Response
|
from rest_framework.response import Response
|
||||||
from rest_framework.serializers import ModelSerializer
|
from rest_framework.serializers import ModelSerializer
|
||||||
|
@ -32,8 +27,8 @@ class SystemTaskSerializer(ModelSerializer):
|
||||||
full_name = SerializerMethodField()
|
full_name = SerializerMethodField()
|
||||||
uid = CharField(required=False)
|
uid = CharField(required=False)
|
||||||
description = CharField()
|
description = CharField()
|
||||||
start_timestamp = DateTimeField()
|
start_timestamp = SerializerMethodField()
|
||||||
finish_timestamp = DateTimeField()
|
finish_timestamp = SerializerMethodField()
|
||||||
duration = SerializerMethodField()
|
duration = SerializerMethodField()
|
||||||
|
|
||||||
status = ChoiceField(choices=[(x.value, x.name) for x in TaskStatus])
|
status = ChoiceField(choices=[(x.value, x.name) for x in TaskStatus])
|
||||||
|
@ -45,9 +40,15 @@ class SystemTaskSerializer(ModelSerializer):
|
||||||
return f"{instance.name}:{instance.uid}"
|
return f"{instance.name}:{instance.uid}"
|
||||||
return instance.name
|
return instance.name
|
||||||
|
|
||||||
def get_duration(self, instance: SystemTask) -> int:
|
def get_start_timestamp(self, instance: SystemTask) -> datetime:
|
||||||
|
return datetime.fromtimestamp(instance.start_timestamp, tz=timezone.utc)
|
||||||
|
|
||||||
|
def get_finish_timestamp(self, instance: SystemTask) -> datetime:
|
||||||
|
return datetime.fromtimestamp(instance.finish_timestamp, tz=timezone.utc)
|
||||||
|
|
||||||
|
def get_duration(self, instance: SystemTask) -> float:
|
||||||
"""Get the duration a task took to run"""
|
"""Get the duration a task took to run"""
|
||||||
return max(instance.finish_timestamp.timestamp() - instance.start_timestamp.timestamp(), 0)
|
return max(instance.finish_timestamp - instance.start_timestamp, 0)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = SystemTask
|
model = SystemTask
|
||||||
|
@ -74,7 +75,7 @@ class SystemTaskViewSet(ReadOnlyModelViewSet):
|
||||||
ordering = ["name", "uid", "status"]
|
ordering = ["name", "uid", "status"]
|
||||||
search_fields = ["name", "description", "uid", "status"]
|
search_fields = ["name", "description", "uid", "status"]
|
||||||
|
|
||||||
@permission_required(None, ["authentik_events.rerun_task"])
|
@permission_required(None, ["authentik_events.run_task"])
|
||||||
@extend_schema(
|
@extend_schema(
|
||||||
request=OpenApiTypes.NONE,
|
request=OpenApiTypes.NONE,
|
||||||
responses={
|
responses={
|
||||||
|
@ -84,21 +85,21 @@ class SystemTaskViewSet(ReadOnlyModelViewSet):
|
||||||
},
|
},
|
||||||
)
|
)
|
||||||
@action(detail=True, methods=["post"])
|
@action(detail=True, methods=["post"])
|
||||||
def retry(self, request: Request, pk=None) -> Response:
|
def run(self, request: Request, pk=None) -> Response:
|
||||||
"""Retry task"""
|
"""Run task"""
|
||||||
task = self.get_object()
|
task: SystemTask = self.get_object()
|
||||||
try:
|
try:
|
||||||
task_module = import_module(task.task_call_module)
|
task_module = import_module(task.task_call_module)
|
||||||
task_func = getattr(task_module, task.task_call_func)
|
task_func = getattr(task_module, task.task_call_func)
|
||||||
LOGGER.debug("Running task", task=task_func)
|
LOGGER.info("Running task", task=task_func)
|
||||||
task_func.delay(*task.task_call_args, **task.task_call_kwargs)
|
task_func.delay(*task.task_call_args, **task.task_call_kwargs)
|
||||||
messages.success(
|
messages.success(
|
||||||
self.request,
|
self.request,
|
||||||
_("Successfully re-scheduled Task %(name)s!" % {"name": task.task_name}),
|
_("Successfully started task %(name)s." % {"name": task.name}),
|
||||||
)
|
)
|
||||||
return Response(status=204)
|
return Response(status=204)
|
||||||
except (ImportError, AttributeError): # pragma: no cover
|
except (ImportError, AttributeError) as exc: # pragma: no cover
|
||||||
LOGGER.warning("Failed to run task, remove state", task=task)
|
LOGGER.warning("Failed to run task, remove state", task=task.name, exc=exc)
|
||||||
# if we get an import error, the module path has probably changed
|
# if we get an import error, the module path has probably changed
|
||||||
task.delete()
|
task.delete()
|
||||||
return Response(status=500)
|
return Response(status=500)
|
||||||
|
|
|
@ -21,7 +21,7 @@ from authentik.core.models import (
|
||||||
UserSourceConnection,
|
UserSourceConnection,
|
||||||
)
|
)
|
||||||
from authentik.enterprise.providers.rac.models import ConnectionToken
|
from authentik.enterprise.providers.rac.models import ConnectionToken
|
||||||
from authentik.events.models import Event, EventAction, Notification
|
from authentik.events.models import Event, EventAction, Notification, SystemTask
|
||||||
from authentik.events.utils import model_to_dict
|
from authentik.events.utils import model_to_dict
|
||||||
from authentik.flows.models import FlowToken, Stage
|
from authentik.flows.models import FlowToken, Stage
|
||||||
from authentik.lib.sentry import before_send
|
from authentik.lib.sentry import before_send
|
||||||
|
@ -56,6 +56,7 @@ IGNORED_MODELS = (
|
||||||
SCIMGroup,
|
SCIMGroup,
|
||||||
Reputation,
|
Reputation,
|
||||||
ConnectionToken,
|
ConnectionToken,
|
||||||
|
SystemTask,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
# Generated by Django 5.0.1 on 2024-01-13 20:14
|
# Generated by Django 5.0.1 on 2024-01-13 21:42
|
||||||
|
|
||||||
import uuid
|
import uuid
|
||||||
|
|
||||||
|
@ -29,8 +29,8 @@ class Migration(migrations.Migration):
|
||||||
),
|
),
|
||||||
("name", models.TextField()),
|
("name", models.TextField()),
|
||||||
("uid", models.TextField(null=True)),
|
("uid", models.TextField(null=True)),
|
||||||
("start_timestamp", models.DateTimeField(auto_now_add=True)),
|
("start_timestamp", models.FloatField()),
|
||||||
("finish_timestamp", models.DateTimeField(auto_now=True)),
|
("finish_timestamp", models.FloatField()),
|
||||||
(
|
(
|
||||||
"status",
|
"status",
|
||||||
models.TextField(
|
models.TextField(
|
||||||
|
@ -52,7 +52,7 @@ class Migration(migrations.Migration):
|
||||||
options={
|
options={
|
||||||
"verbose_name": "System Task",
|
"verbose_name": "System Task",
|
||||||
"verbose_name_plural": "System Tasks",
|
"verbose_name_plural": "System Tasks",
|
||||||
"permissions": [("rerun_task", "Rerun task")],
|
"permissions": [("run_task", "Run task")],
|
||||||
"default_permissions": ["view"],
|
"default_permissions": ["view"],
|
||||||
"unique_together": {("name", "uid")},
|
"unique_together": {("name", "uid")},
|
||||||
},
|
},
|
||||||
|
|
|
@ -601,8 +601,8 @@ class SystemTask(SerializerModel, ExpiringModel):
|
||||||
name = models.TextField()
|
name = models.TextField()
|
||||||
uid = models.TextField(null=True)
|
uid = models.TextField(null=True)
|
||||||
|
|
||||||
start_timestamp = models.DateTimeField(auto_now_add=True)
|
start_timestamp = models.FloatField()
|
||||||
finish_timestamp = models.DateTimeField(auto_now=True)
|
finish_timestamp = models.FloatField()
|
||||||
|
|
||||||
status = models.TextField(choices=TaskStatus.choices)
|
status = models.TextField(choices=TaskStatus.choices)
|
||||||
|
|
||||||
|
@ -636,6 +636,6 @@ class SystemTask(SerializerModel, ExpiringModel):
|
||||||
unique_together = (("name", "uid"),)
|
unique_together = (("name", "uid"),)
|
||||||
# Remove "add", "change" and "delete" permissions as those are not used
|
# Remove "add", "change" and "delete" permissions as those are not used
|
||||||
default_permissions = ["view"]
|
default_permissions = ["view"]
|
||||||
permissions = [("rerun_task", _("Rerun task"))]
|
permissions = [("run_task", _("Run task"))]
|
||||||
verbose_name = _("System Task")
|
verbose_name = _("System Task")
|
||||||
verbose_name_plural = _("System Tasks")
|
verbose_name_plural = _("System Tasks")
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
"""Monitored tasks"""
|
"""Monitored tasks"""
|
||||||
from datetime import datetime, timedelta, timezone
|
from datetime import timedelta
|
||||||
from timeit import default_timer
|
from timeit import default_timer
|
||||||
from typing import Any, Optional
|
from typing import Any, Optional
|
||||||
|
|
||||||
|
@ -69,10 +69,8 @@ class MonitoredTask(Task):
|
||||||
uid=self._uid,
|
uid=self._uid,
|
||||||
defaults={
|
defaults={
|
||||||
"description": self.__doc__,
|
"description": self.__doc__,
|
||||||
"start_timestamp": datetime.fromtimestamp(
|
"start_timestamp": self._start or default_timer(),
|
||||||
self._start or default_timer(), tz=timezone.utc
|
"finish_timestamp": default_timer(),
|
||||||
),
|
|
||||||
"finish_timestamp": datetime.fromtimestamp(default_timer(), tz=timezone.utc),
|
|
||||||
"task_call_module": self.__module__,
|
"task_call_module": self.__module__,
|
||||||
"task_call_func": self.__name__,
|
"task_call_func": self.__name__,
|
||||||
"task_call_args": args,
|
"task_call_args": args,
|
||||||
|
@ -95,10 +93,8 @@ class MonitoredTask(Task):
|
||||||
uid=self._uid,
|
uid=self._uid,
|
||||||
defaults={
|
defaults={
|
||||||
"description": self.__doc__,
|
"description": self.__doc__,
|
||||||
"start_timestamp": datetime.fromtimestamp(
|
"start_timestamp": self._start or default_timer(),
|
||||||
self._start or default_timer(), tz=timezone.utc
|
"finish_timestamp": default_timer(),
|
||||||
),
|
|
||||||
"finish_timestamp": datetime.fromtimestamp(default_timer(), tz=timezone.utc),
|
|
||||||
"task_call_module": self.__module__,
|
"task_call_module": self.__module__,
|
||||||
"task_call_func": self.__name__,
|
"task_call_func": self.__name__,
|
||||||
"task_call_args": args,
|
"task_call_args": args,
|
||||||
|
|
|
@ -3252,16 +3252,6 @@
|
||||||
"minLength": 1,
|
"minLength": 1,
|
||||||
"title": "Description"
|
"title": "Description"
|
||||||
},
|
},
|
||||||
"start_timestamp": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "date-time",
|
|
||||||
"title": "Start timestamp"
|
|
||||||
},
|
|
||||||
"finish_timestamp": {
|
|
||||||
"type": "string",
|
|
||||||
"format": "date-time",
|
|
||||||
"title": "Finish timestamp"
|
|
||||||
},
|
|
||||||
"status": {
|
"status": {
|
||||||
"type": "string",
|
"type": "string",
|
||||||
"enum": [
|
"enum": [
|
||||||
|
|
11
schema.yml
11
schema.yml
|
@ -6944,10 +6944,10 @@ paths:
|
||||||
schema:
|
schema:
|
||||||
$ref: '#/components/schemas/GenericError'
|
$ref: '#/components/schemas/GenericError'
|
||||||
description: ''
|
description: ''
|
||||||
/events/system_tasks/{uuid}/retry/:
|
/events/system_tasks/{uuid}/run/:
|
||||||
post:
|
post:
|
||||||
operationId: events_system_tasks_retry_create
|
operationId: events_system_tasks_run_create
|
||||||
description: Retry task
|
description: Run task
|
||||||
parameters:
|
parameters:
|
||||||
- in: path
|
- in: path
|
||||||
name: uuid
|
name: uuid
|
||||||
|
@ -42719,11 +42719,14 @@ components:
|
||||||
start_timestamp:
|
start_timestamp:
|
||||||
type: string
|
type: string
|
||||||
format: date-time
|
format: date-time
|
||||||
|
readOnly: true
|
||||||
finish_timestamp:
|
finish_timestamp:
|
||||||
type: string
|
type: string
|
||||||
format: date-time
|
format: date-time
|
||||||
|
readOnly: true
|
||||||
duration:
|
duration:
|
||||||
type: integer
|
type: number
|
||||||
|
format: double
|
||||||
description: Get the duration a task took to run
|
description: Get the duration a task took to run
|
||||||
readOnly: true
|
readOnly: true
|
||||||
status:
|
status:
|
||||||
|
|
|
@ -113,7 +113,7 @@ export class SystemTaskListPage extends TablePage<SystemTask> {
|
||||||
class="pf-m-plain"
|
class="pf-m-plain"
|
||||||
.apiRequest=${() => {
|
.apiRequest=${() => {
|
||||||
return new EventsApi(DEFAULT_CONFIG)
|
return new EventsApi(DEFAULT_CONFIG)
|
||||||
.eventsSystemTasksRetryCreate({
|
.eventsSystemTasksRunCreate({
|
||||||
uuid: item.uuid,
|
uuid: item.uuid,
|
||||||
})
|
})
|
||||||
.then(() => {
|
.then(() => {
|
||||||
|
|
Reference in New Issue