Skip to content

Commit

Permalink
规则:固定时间频率支持多个时间
Browse files Browse the repository at this point in the history
  • Loading branch information
mylxsw committed Jul 10, 2020
1 parent b03f58f commit 305ff10
Show file tree
Hide file tree
Showing 7 changed files with 105 additions and 27 deletions.
27 changes: 17 additions & 10 deletions api/controller/rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,9 @@ type RuleForm struct {
Description string `json:"description"`
Tags []string `json:"tags"`

ReadyType string `json:"ready_type"`
Interval int64 `json:"interval"`
DailyTime string `json:"daily_time"`
ReadyType string `json:"ready_type"`
Interval int64 `json:"interval"`
DailyTimes []string `json:"daily_times"`

Rule string `json:"rule"`
Template string `json:"template"`
Expand Down Expand Up @@ -92,14 +92,21 @@ func (r RuleForm) Validate(req web.Request) error {
return errors.New("interval is invalid, must between 1min~24h")
}
case repository.ReadyTypeDailyTime:
if len(r.DailyTime) < 5 {
return fmt.Errorf("invalid daily_time format")
if len(r.DailyTimes) == 0 {
return fmt.Errorf("daily_times is required")
}

_, err := time.Parse("15:04", r.DailyTime[:5])
if err != nil {
return fmt.Errorf("invalid daily_time format: %v", err)
for _, dailyTime := range r.DailyTimes {
if len(dailyTime) < 5 {
return fmt.Errorf("invalid daily_time format for %s", dailyTime)
}

_, err := time.Parse("15:04", dailyTime[:5])
if err != nil {
return fmt.Errorf("invalid daily_time format for %s: %v", dailyTime, err)
}
}

default:
return errors.New("invalid readyType")
}
Expand Down Expand Up @@ -201,7 +208,7 @@ func (r RuleController) Add(ctx web.Context, repo repository.RuleRepo, manager a
Description: ruleForm.Description,
Tags: ruleForm.Tags,
ReadyType: ruleForm.ReadyType,
DailyTime: ruleForm.DailyTime,
DailyTimes: array.StringUnique(ruleForm.DailyTimes),
Interval: ruleForm.Interval,
Rule: ruleForm.Rule,
Template: ruleForm.Template,
Expand Down Expand Up @@ -268,7 +275,7 @@ func (r RuleController) Update(ctx web.Context, ruleRepo repository.RuleRepo, ma
Description: ruleForm.Description,
Tags: ruleForm.Tags,
ReadyType: ruleForm.ReadyType,
DailyTime: ruleForm.DailyTime,
DailyTimes: array.StringUnique(ruleForm.DailyTimes),
Interval: ruleForm.Interval,
Rule: ruleForm.Rule,
Template: ruleForm.Template,
Expand Down
2 changes: 1 addition & 1 deletion dashboard/src/App.vue
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
<b-navbar-brand href="/">Adanos</b-navbar-brand>
<b-collapse is-nav id="nav_dropdown_collapse">
<b-navbar-nav>
<b-nav-item to="/" exact>分组</b-nav-item>
<b-nav-item href="/" exact>分组</b-nav-item>
<b-nav-item :to="{path:'/messages', query: {status: null}}" exact>
消息
<b-badge variant="danger" v-if="pending_message_count > 0" v-b-tooltip.hover title="没有匹配任何规则的消息">{{ pending_message_count }}</b-badge>
Expand Down
1 change: 1 addition & 0 deletions dashboard/src/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ Vue.prototype.ToastSuccess = function (message) {
};

Vue.prototype.ToastError = function (message) {
console.log("Error: ", message);
this.$bvToast.toast(this.ParseError(message), {
title: 'ERROR',
variant: 'danger'
Expand Down
27 changes: 23 additions & 4 deletions dashboard/src/views/RuleEdit.vue
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,13 @@
v-model="form.interval" required/>
</b-form-group>
<b-form-group label-cols="2" label="时间" v-if="form.ready_type === 'daily_time'">
<b-form-timepicker v-model="form.daily_time" :hour12="false" :show-seconds="false"></b-form-timepicker>
<b-btn variant="success" class="mb-3" @click="dailyTimeAdd()">添加</b-btn>
<b-input-group v-bind:key="i" v-for="(daily_time, i) in form.daily_times" style="margin-bottom: 10px;">
<b-form-timepicker v-model="form.daily_times[i]" :hour12="false" :show-seconds="false"></b-form-timepicker>
<b-input-group-append>
<b-btn variant="danger" @click="dailyTimeDelete(i)">删除</b-btn>
</b-input-group-append>
</b-input-group>
</b-form-group>
</div>
</b-form-group>
Expand Down Expand Up @@ -493,7 +499,7 @@
description: '',
tags: [],
ready_type: 'interval',
daily_time: '09:00:00',
daily_times: ['09:00:00'],
interval: 1,
rule: '',
template: '',
Expand Down Expand Up @@ -722,6 +728,19 @@
triggerDelete(index) {
this.form.triggers.splice(index, 1);
},
/**
* 添加执行时间
*/
dailyTimeAdd() {
this.form.daily_times.push('09:00:00');
},
/**
* 删除执行时间
* @param index
*/
dailyTimeDelete(index) {
this.form.daily_times.splice(index, 1);
},
/**
* 保存
* @param evt
Expand Down Expand Up @@ -767,7 +786,7 @@
requestData.interval = this.form.interval * 60;
}
} else {
requestData.daily_time = this.form.daily_time.substring(0, 5);
requestData.daily_times = this.form.daily_times;
}
return requestData;
Expand All @@ -784,7 +803,7 @@
this.form.description = response.data.description;
this.form.interval = response.data.interval / 60;
this.form.ready_type = response.data.ready_type === '' ? 'interval': response.data.ready_type;
this.form.daily_time = response.data.daily_time === '' ? '09:00:00' : response.data.daily_time;
this.form.daily_times = (response.data.daily_times === null || response.data.daily_times.length === 0) ? ['09:00:00'] : response.data.daily_times;
this.form.rule = response.data.rule;
this.form.tags = response.data.tags;
this.form.template = response.data.template;
Expand Down
3 changes: 2 additions & 1 deletion dashboard/src/views/Rules.vue
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
<p><small>
频率为
<span v-if="row.item.ready_type === 'interval' || row.item.ready_type === ''"><code><b>{{ row.item.interval / 60 }} 分钟每次</b></code></span>
<span v-if="row.item.ready_type === 'daily_time'"><code><b>每天 {{ row.item.daily_time }}</b></code></span>
<span v-if="row.item.ready_type === 'daily_time'"><code><b>每天 {{ row.item.daily_times.map((t) => t.substring(0, 5)).join(", ")}}</b></code></span>
{{ row.item.description !== '' ? '':''}} {{ row.item.description }}</small></p>
<p class="adanos-pre-fold" v-b-tooltip.hover :title="row.item.rule"><code>{{ row.item.rule }}</code></p>
</template>
Expand Down Expand Up @@ -55,6 +55,7 @@
</template>
<template v-slot:cell(operations)="row">
<b-button-group>
<b-button size="sm" variant="success" :to="{path:'/', query:{rule_id: row.item.id}}">报警</b-button>
<b-button size="sm" variant="warning" :to="{path:'/rules/add', query: {copy_from: row.item.id}}" target="_blank">复制</b-button>
<b-button size="sm" variant="info" :to="{path:'/rules/' + row.item.id + '/edit'}">编辑</b-button>
<b-button size="sm" variant="danger" @click="delete_rule(row.index, row.item.id)">删除</b-button>
Expand Down
47 changes: 38 additions & 9 deletions internal/repository/rule.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
package repository

import (
"sort"
"time"

"github.com/mylxsw/asteria/log"
"github.com/mylxsw/coll"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/bson/primitive"
)
Expand Down Expand Up @@ -33,9 +35,9 @@ type Rule struct {
Tags []string `bson:"tags" json:"tags"`

// ReadType 就绪类型,支持 interval/daily_time
ReadyType string `bson:"ready_type" json:"ready_type"`
Interval int64 `bson:"interval" json:"interval"`
DailyTime string `bson:"daily_time" json:"daily_time"`
ReadyType string `bson:"ready_type" json:"ready_type"`
Interval int64 `bson:"interval" json:"interval"`
DailyTimes []string `bson:"daily_times" json:"daily_times"`

Rule string `bson:"rule" json:"rule"`
Template string `bson:"template" json:"template"`
Expand Down Expand Up @@ -66,7 +68,7 @@ func (rule Rule) ToGroupRule() MessageGroupRule {
case ReadyTypeInterval:
groupRule.ExpectReadyAt = time.Now().Add(time.Duration(rule.Interval) * time.Second)
case ReadyTypeDailyTime:
groupRule.ExpectReadyAt = ExpectReadyAt(rule.DailyTime)
groupRule.ExpectReadyAt = ExpectReadyAt(time.Now(), rule.DailyTimes)
default:
log.Errorf("invalid readyType [%s] for ruleID=%s", rule.ReadyType, rule.ID.Hex())
}
Expand All @@ -87,9 +89,36 @@ type RuleRepo interface {
Tags() ([]Tag, error)
}

func ExpectReadyAt(dailyTime string) time.Time {
// 2006-01-02T15:04:05Z07:00
nextDayTimeStr := time.Now().Add(24 * time.Hour).Format(time.RFC3339)
parsed, _ := time.Parse(time.RFC3339, nextDayTimeStr[0:11]+dailyTime[:5]+":00"+nextDayTimeStr[19:])
return parsed
func ExpectReadyAt(now time.Time, dailyTimes []string) time.Time {
// 查找最近的时间点
var times Times
todayTimeStr := now.Format(time.RFC3339)
_ = coll.MustNew(dailyTimes).Map(func(dailyTime string) time.Time {
ts, _ := time.Parse(time.RFC3339, todayTimeStr[0:11]+dailyTime[:5]+":00"+todayTimeStr[19:])
return ts
}).All(&times)

sort.Sort(times)

for _, t := range times {
if now.Before(t) {
return t
}
}

return times[0].Add(24 * time.Hour)
}

type Times []time.Time

func (t Times) Len() int {
return len(t)
}

func (t Times) Less(i, j int) bool {
return t[i].Before(t[j])
}

func (t Times) Swap(i, j int) {
t[i], t[j] = t[j], t[i]
}
25 changes: 23 additions & 2 deletions internal/repository/rule_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,33 @@
package repository_test

import (
"fmt"
"testing"
"time"

"github.com/mylxsw/adanos-alert/internal/repository"
"github.com/stretchr/testify/assert"
)

func TestExpectReadyAt(t *testing.T) {
fmt.Println(repository.ExpectReadyAt("09:00"))
var times = []string{"09:00", "04:00", "12:00", "23:50", "15:30", "18:00"}

{
rs := repository.ExpectReadyAt(parseTime("2020-07-10T23:55:16+08:00"), times).Format(time.RFC3339)
assert.Equal(t, "2020-07-11T04:00:00+08:00", rs)
}

{
rs := repository.ExpectReadyAt(parseTime("2020-07-10T20:55:16+08:00"), times).Format(time.RFC3339)
assert.Equal(t, "2020-07-10T23:50:00+08:00", rs)
}

{
rs := repository.ExpectReadyAt(parseTime("2020-07-10T09:55:16+08:00"), times).Format(time.RFC3339)
assert.Equal(t, "2020-07-10T12:00:00+08:00", rs)
}
}

func parseTime(t string) time.Time {
p, _ := time.Parse(time.RFC3339, t)
return p
}

0 comments on commit 305ff10

Please sign in to comment.