mirror of https://github.com/openspug/spug
				
				
				
			U api update
							parent
							
								
									5632ed1ea7
								
							
						
					
					
						commit
						980bef2d83
					
				| 
						 | 
				
			
			@ -2,10 +2,12 @@ from apscheduler.schedulers.background import BackgroundScheduler
 | 
			
		|||
from apscheduler.triggers.interval import IntervalTrigger
 | 
			
		||||
from apscheduler import events
 | 
			
		||||
from django_redis import get_redis_connection
 | 
			
		||||
from django.utils.functional import SimpleLazyObject
 | 
			
		||||
from apps.monitor.models import Detection
 | 
			
		||||
from apps.alarm.models import Alarm
 | 
			
		||||
from apps.monitor.executors import dispatch
 | 
			
		||||
from apps.monitor.utils import seconds_to_human
 | 
			
		||||
from apps.notify.models import Notify
 | 
			
		||||
from django.conf import settings
 | 
			
		||||
from libs import AttrDict, human_datetime
 | 
			
		||||
import logging
 | 
			
		||||
| 
						 | 
				
			
			@ -13,6 +15,7 @@ import json
 | 
			
		|||
import time
 | 
			
		||||
 | 
			
		||||
logger = logging.getLogger("django.apps.monitor")
 | 
			
		||||
counter = dict()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Scheduler:
 | 
			
		||||
| 
						 | 
				
			
			@ -46,16 +49,36 @@ class Scheduler:
 | 
			
		|||
                    logger.info(f'{human_datetime()} notify job_id: {obj.id}')
 | 
			
		||||
 | 
			
		||||
    def _handle_event(self, event):
 | 
			
		||||
        # TODO: notify to user
 | 
			
		||||
        obj = SimpleLazyObject(lambda: Detection.objects.filter(pk=event.job_id).first())
 | 
			
		||||
        if event.code == events.EVENT_SCHEDULER_SHUTDOWN:
 | 
			
		||||
            logger.info(f'EVENT_SCHEDULER_SHUTDOWN: {event}')
 | 
			
		||||
        if event.code == events.EVENT_JOB_MAX_INSTANCES:
 | 
			
		||||
            Notify.objects.create(
 | 
			
		||||
                title='调度器已关闭',
 | 
			
		||||
                source='monitor',
 | 
			
		||||
                content='调度器意外关闭,你可以在github上提交issue',
 | 
			
		||||
                type='1',
 | 
			
		||||
            )
 | 
			
		||||
        elif event.code == events.EVENT_JOB_MAX_INSTANCES:
 | 
			
		||||
            logger.info(f'EVENT_JOB_MAX_INSTANCES: {event}')
 | 
			
		||||
        if event.code == events.EVENT_JOB_ERROR:
 | 
			
		||||
            if time.time() - counter.get(event.job_id, time.time()) > 3600:
 | 
			
		||||
                counter[event.job_id] = time.time()
 | 
			
		||||
                Notify.objects.create(
 | 
			
		||||
                    title=f'{obj.name} - 达到调度实例上限',
 | 
			
		||||
                    source='monitor',
 | 
			
		||||
                    content='一般为上个周期的执行任务还未结束,请增加调度间隔或减少任务执行耗时',
 | 
			
		||||
                    type='1',
 | 
			
		||||
                )
 | 
			
		||||
        elif event.code == events.EVENT_JOB_ERROR:
 | 
			
		||||
            logger.info(f'EVENT_JOB_ERROR: job_id {event.job_id} exception: {event.exception}')
 | 
			
		||||
        if event.code == events.EVENT_JOB_MISSED:
 | 
			
		||||
            logger.info(f'EVENT_JOB_MISSED: job_id {event.job_id}')
 | 
			
		||||
        if event.code == events.EVENT_JOB_EXECUTED:
 | 
			
		||||
            if time.time() - counter.get(event.job_id, time.time()) > 3600:
 | 
			
		||||
                counter[event.job_id] = time.time()
 | 
			
		||||
                Notify.objects.create(
 | 
			
		||||
                    title=f'{obj.name} - 执行异常',
 | 
			
		||||
                    source='monitor',
 | 
			
		||||
                    content=f'{event.exception}',
 | 
			
		||||
                    type='1',
 | 
			
		||||
                )
 | 
			
		||||
        elif event.code == events.EVENT_JOB_EXECUTED:
 | 
			
		||||
            obj = Detection.objects.filter(pk=event.job_id).first()
 | 
			
		||||
            old_status = obj.latest_status
 | 
			
		||||
            obj.latest_status = 0 if event.retval else 1
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -0,0 +1,28 @@
 | 
			
		|||
from django.db import models
 | 
			
		||||
from libs import ModelMixin, human_datetime
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Notify(models.Model, ModelMixin):
 | 
			
		||||
    TYPES = (
 | 
			
		||||
        ('1', '通知'),
 | 
			
		||||
        ('2', '待办'),
 | 
			
		||||
    )
 | 
			
		||||
    SOURCES = (
 | 
			
		||||
        ('monitor', '监控中心'),
 | 
			
		||||
        ('schedule', '任务计划'),
 | 
			
		||||
    )
 | 
			
		||||
    title = models.CharField(max_length=255)
 | 
			
		||||
    source = models.CharField(max_length=10, choices=SOURCES)
 | 
			
		||||
    type = models.CharField(max_length=2, choices=TYPES)
 | 
			
		||||
    content = models.CharField(max_length=255, null=True)
 | 
			
		||||
    unread = models.BooleanField(default=True)
 | 
			
		||||
    link = models.CharField(max_length=255, null=True)
 | 
			
		||||
 | 
			
		||||
    created_at = models.CharField(max_length=20, default=human_datetime)
 | 
			
		||||
 | 
			
		||||
    def __repr__(self):
 | 
			
		||||
        return '<Notify %r>' % self.title
 | 
			
		||||
 | 
			
		||||
    class Meta:
 | 
			
		||||
        db_table = 'notifies'
 | 
			
		||||
        ordering = ('-id',)
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,7 @@
 | 
			
		|||
from django.urls import path
 | 
			
		||||
 | 
			
		||||
from .views import *
 | 
			
		||||
 | 
			
		||||
urlpatterns = [
 | 
			
		||||
    path('', NotifyView.as_view()),
 | 
			
		||||
]
 | 
			
		||||
| 
						 | 
				
			
			@ -0,0 +1,17 @@
 | 
			
		|||
from django.views.generic import View
 | 
			
		||||
from apps.notify.models import Notify
 | 
			
		||||
from libs import json_response, JsonParser, Argument
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class NotifyView(View):
 | 
			
		||||
    def get(self, request):
 | 
			
		||||
        notifies = Notify.objects.filter(unread=True)
 | 
			
		||||
        return json_response(notifies)
 | 
			
		||||
 | 
			
		||||
    def patch(self, request):
 | 
			
		||||
        form, error = JsonParser(
 | 
			
		||||
            Argument('id', type=int, help='参数错误')
 | 
			
		||||
        ).parse(request.body)
 | 
			
		||||
        if error is None:
 | 
			
		||||
            Notify.objects.filter(pk=form.id).update(unread=False)
 | 
			
		||||
        return json_response(error=error)
 | 
			
		||||
| 
						 | 
				
			
			@ -3,15 +3,19 @@ from apscheduler.triggers.interval import IntervalTrigger
 | 
			
		|||
from apscheduler.triggers.date import DateTrigger
 | 
			
		||||
from apscheduler import events
 | 
			
		||||
from django_redis import get_redis_connection
 | 
			
		||||
from django.utils.functional import SimpleLazyObject
 | 
			
		||||
from apps.schedule.models import Task
 | 
			
		||||
from apps.notify.models import Notify
 | 
			
		||||
from apps.schedule.executors import dispatch
 | 
			
		||||
from apps.alarm.utils import auto_clean_records
 | 
			
		||||
from django.conf import settings
 | 
			
		||||
from libs import AttrDict, human_datetime
 | 
			
		||||
import logging
 | 
			
		||||
import json
 | 
			
		||||
import time
 | 
			
		||||
 | 
			
		||||
logger = logging.getLogger("django.apps.scheduler")
 | 
			
		||||
counter = dict()
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
class Scheduler:
 | 
			
		||||
| 
						 | 
				
			
			@ -31,16 +35,36 @@ class Scheduler:
 | 
			
		|||
            raise TypeError(f'unknown schedule policy: {trigger!r}')
 | 
			
		||||
 | 
			
		||||
    def _handle_event(self, event):
 | 
			
		||||
        # TODO: notify to user
 | 
			
		||||
        obj = SimpleLazyObject(lambda: Task.objects.filter(pk=event.job_id).first())
 | 
			
		||||
        if event.code == events.EVENT_SCHEDULER_SHUTDOWN:
 | 
			
		||||
            logger.info(f'EVENT_SCHEDULER_SHUTDOWN: {event}')
 | 
			
		||||
        if event.code == events.EVENT_JOB_MAX_INSTANCES:
 | 
			
		||||
            Notify.objects.create(
 | 
			
		||||
                title='调度器已关闭',
 | 
			
		||||
                source='schedule',
 | 
			
		||||
                content='调度器意外关闭,你可以在github上提交issue',
 | 
			
		||||
                type='1',
 | 
			
		||||
            )
 | 
			
		||||
        elif event.code == events.EVENT_JOB_MAX_INSTANCES:
 | 
			
		||||
            logger.info(f'EVENT_JOB_MAX_INSTANCES: {event}')
 | 
			
		||||
        if event.code == events.EVENT_JOB_ERROR:
 | 
			
		||||
            if time.time() - counter.get(event.job_id, 0) > 3600:
 | 
			
		||||
                counter[event.job_id] = time.time()
 | 
			
		||||
                Notify.objects.create(
 | 
			
		||||
                    title=f'{obj.name} - 达到调度实例上限',
 | 
			
		||||
                    source='schedule',
 | 
			
		||||
                    content='一般为上个周期的执行任务还未结束,请增加调度间隔或减少任务执行耗时',
 | 
			
		||||
                    type='1',
 | 
			
		||||
                )
 | 
			
		||||
        elif event.code == events.EVENT_JOB_ERROR:
 | 
			
		||||
            logger.info(f'EVENT_JOB_ERROR: job_id {event.job_id} exception: {event.exception}')
 | 
			
		||||
        if event.code == events.EVENT_JOB_MISSED:
 | 
			
		||||
            logger.info(f'EVENT_JOB_MISSED: job_id {event.job_id}')
 | 
			
		||||
        if event.code == events.EVENT_JOB_EXECUTED:
 | 
			
		||||
            if time.time() - counter.get(event.job_id, 0) > 3600:
 | 
			
		||||
                counter[event.job_id] = time.time()
 | 
			
		||||
                Notify.objects.create(
 | 
			
		||||
                    title=f'{obj.name} - 执行异常',
 | 
			
		||||
                    source='schedule',
 | 
			
		||||
                    content=f'{event.exception}',
 | 
			
		||||
                    type='1',
 | 
			
		||||
                )
 | 
			
		||||
        elif event.code == events.EVENT_JOB_EXECUTED:
 | 
			
		||||
            if event.retval:
 | 
			
		||||
                score = 0
 | 
			
		||||
                for item in event.retval:
 | 
			
		||||
| 
						 | 
				
			
			@ -50,6 +74,14 @@ class Scheduler:
 | 
			
		|||
                    latest_run_time=human_datetime(event.scheduled_run_time),
 | 
			
		||||
                    latest_output=json.dumps(event.retval)
 | 
			
		||||
                )
 | 
			
		||||
                if score != 0 and time.time() - counter.get(event.job_id, 0) > 3600:
 | 
			
		||||
                    counter[event.job_id] = time.time()
 | 
			
		||||
                    Notify.objects.create(
 | 
			
		||||
                        title=f'{obj.name} - 执行失败',
 | 
			
		||||
                        source='schedule',
 | 
			
		||||
                        content='请在任务计划中查看失败详情',
 | 
			
		||||
                        type='1',
 | 
			
		||||
                    )
 | 
			
		||||
 | 
			
		||||
    def _init_builtin_jobs(self):
 | 
			
		||||
        self.scheduler.add_job(auto_clean_records, 'cron', hour=0, minute=0)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -41,6 +41,7 @@ INSTALLED_APPS = [
 | 
			
		|||
    'apps.config',
 | 
			
		||||
    'apps.app',
 | 
			
		||||
    'apps.deploy',
 | 
			
		||||
    'apps.notify',
 | 
			
		||||
]
 | 
			
		||||
 | 
			
		||||
MIDDLEWARE = [
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -27,5 +27,6 @@ urlpatterns = [
 | 
			
		|||
    path('app/', include('apps.app.urls')),
 | 
			
		||||
    path('deploy/', include('apps.deploy.urls')),
 | 
			
		||||
    path('home/', include('apps.home.urls')),
 | 
			
		||||
    path('notify/', include('apps.notify.urls')),
 | 
			
		||||
    path('apis/', include('apps.apis.urls')),
 | 
			
		||||
]
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue