crono_trigger 0.3.2 → 0.3.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.travis.yml +1 -2
- data/README.md +40 -0
- data/Rakefile +17 -0
- data/crono_trigger.gemspec +4 -1
- data/exe/crono_trigger-web +33 -0
- data/lib/crono_trigger.rb +20 -2
- data/lib/crono_trigger/cli.rb +8 -3
- data/lib/crono_trigger/models/signal.rb +52 -0
- data/lib/crono_trigger/models/worker.rb +16 -0
- data/lib/crono_trigger/polling_thread.rb +58 -20
- data/lib/crono_trigger/railtie.rb +15 -0
- data/lib/crono_trigger/schedulable.rb +69 -17
- data/lib/crono_trigger/version.rb +1 -1
- data/lib/crono_trigger/web.rb +163 -0
- data/lib/crono_trigger/worker.rb +118 -8
- data/lib/generators/crono_trigger/install/install_generator.rb +16 -0
- data/lib/generators/crono_trigger/install/templates/install.rb +23 -0
- data/lib/generators/crono_trigger/migration/templates/create_table_migration.rb +1 -0
- data/lib/generators/crono_trigger/migration/templates/migration.rb +1 -0
- data/web/app/.gitignore +21 -0
- data/web/app/README.md +2448 -0
- data/web/app/images.d.ts +3 -0
- data/web/app/package-lock.json +12439 -0
- data/web/app/package.json +36 -0
- data/web/app/public/favicon.ico +0 -0
- data/web/app/public/index.html +45 -0
- data/web/app/public/manifest.json +8 -0
- data/web/app/src/App.css +5 -0
- data/web/app/src/App.test.tsx +9 -0
- data/web/app/src/App.tsx +91 -0
- data/web/app/src/Models.tsx +61 -0
- data/web/app/src/SchedulableRecord.tsx +208 -0
- data/web/app/src/SchedulableRecordTableCell.tsx +19 -0
- data/web/app/src/SchedulableRecords.tsx +110 -0
- data/web/app/src/Signal.tsx +21 -0
- data/web/app/src/Signals.tsx +74 -0
- data/web/app/src/Worker.tsx +106 -0
- data/web/app/src/Workers.tsx +78 -0
- data/web/app/src/index.css +5 -0
- data/web/app/src/index.tsx +15 -0
- data/web/app/src/interfaces.ts +77 -0
- data/web/app/tsconfig.json +30 -0
- data/web/app/tsconfig.prod.json +3 -0
- data/web/app/tsconfig.test.json +6 -0
- data/web/app/tslint.json +13 -0
- data/web/public/asset-manifest.json +6 -0
- data/web/public/favicon.ico +0 -0
- data/web/public/manifest.json +8 -0
- data/web/public/service-worker.js +1 -0
- data/web/public/static/css/main.0f826673.css +2 -0
- data/web/public/static/css/main.0f826673.css.map +1 -0
- data/web/public/static/js/main.1413dc51.js +2 -0
- data/web/public/static/js/main.1413dc51.js.map +1 -0
- data/web/views/index.erb +1 -0
- data/web/views/signals.erb +9 -0
- data/web/views/workers.erb +9 -0
- metadata +89 -3
@@ -0,0 +1,19 @@
|
|
1
|
+
import { createStyles, withStyles, WithStyles } from '@material-ui/core/styles';
|
2
|
+
import TableCell from '@material-ui/core/TableCell';
|
3
|
+
import * as React from 'react';
|
4
|
+
|
5
|
+
const styles = createStyles({
|
6
|
+
property: {
|
7
|
+
padding: "4px 16px 4px 8px"
|
8
|
+
}
|
9
|
+
});
|
10
|
+
|
11
|
+
interface ITableCellProps extends WithStyles<typeof styles> {
|
12
|
+
children: string | number | null | React.ReactNode | React.ReactNode[],
|
13
|
+
}
|
14
|
+
|
15
|
+
const SchedulableRecordTableCell = withStyles(styles)((props: ITableCellProps) => (
|
16
|
+
<TableCell className={props.classes.property}>{props.children}</TableCell>
|
17
|
+
));
|
18
|
+
|
19
|
+
export default SchedulableRecordTableCell;
|
@@ -0,0 +1,110 @@
|
|
1
|
+
import FormControl from '@material-ui/core/FormControl';
|
2
|
+
import Paper from '@material-ui/core/Paper';
|
3
|
+
import Table from '@material-ui/core/Table';
|
4
|
+
import TableBody from '@material-ui/core/TableBody';
|
5
|
+
import TableHead from '@material-ui/core/TableHead';
|
6
|
+
import TableRow from '@material-ui/core/TableRow';
|
7
|
+
import TextField from '@material-ui/core/TextField';
|
8
|
+
import { debounce } from 'lodash';
|
9
|
+
import * as React from 'react';
|
10
|
+
|
11
|
+
import { IGlobalWindow, ISchedulableRecordsProps, ISchedulableRecordsStates } from './interfaces';
|
12
|
+
import SchedulableRecord from './SchedulableRecord';
|
13
|
+
import SchedulableRecordTableCell from './SchedulableRecordTableCell';
|
14
|
+
|
15
|
+
declare var window: IGlobalWindow;
|
16
|
+
|
17
|
+
class SchedulableRecords extends React.Component<ISchedulableRecordsProps, ISchedulableRecordsStates> {
|
18
|
+
private fetchLoop: any;
|
19
|
+
|
20
|
+
private handleTimeRangeFilterChange = debounce((event: any) => {
|
21
|
+
this.setState({timeRangeMinute: parseInt(event.target.value, 10)});
|
22
|
+
this.fetchSchedulableRecord();
|
23
|
+
}, 500)
|
24
|
+
|
25
|
+
constructor(props: ISchedulableRecordsProps) {
|
26
|
+
super(props);
|
27
|
+
|
28
|
+
this.state = {records: [], timeRangeMinute: 10};
|
29
|
+
}
|
30
|
+
|
31
|
+
public componentDidMount() {
|
32
|
+
this.fetchSchedulableRecord();
|
33
|
+
this.setFetchSchedulableRecordLoop();
|
34
|
+
}
|
35
|
+
|
36
|
+
public componentWillUnmount() {
|
37
|
+
if (this.fetchLoop) {
|
38
|
+
clearTimeout(this.fetchLoop);
|
39
|
+
}
|
40
|
+
}
|
41
|
+
|
42
|
+
public setFetchSchedulableRecordLoop(): void {
|
43
|
+
this.fetchLoop = setTimeout(() => {
|
44
|
+
this.fetchSchedulableRecord();
|
45
|
+
this.setFetchSchedulableRecordLoop();
|
46
|
+
}, 3000);
|
47
|
+
}
|
48
|
+
|
49
|
+
public fetchSchedulableRecord(): void {
|
50
|
+
const that = this;
|
51
|
+
fetch(`${window.mountPath}/models/${this.props.model_name}.json?after=${this.state.timeRangeMinute}`)
|
52
|
+
.then((res) => res.json())
|
53
|
+
.then((data) => {
|
54
|
+
that.setState(data);
|
55
|
+
}).catch((err) => {
|
56
|
+
console.error(err);
|
57
|
+
});
|
58
|
+
}
|
59
|
+
|
60
|
+
public render() {
|
61
|
+
return (
|
62
|
+
<div id="schedulable-models">
|
63
|
+
<FormControl className="filter-form">
|
64
|
+
<TextField
|
65
|
+
id="time-range-input"
|
66
|
+
label="Time Range"
|
67
|
+
type="number"
|
68
|
+
defaultValue={this.state.timeRangeMinute}
|
69
|
+
helperText="minute after"
|
70
|
+
margin="normal"
|
71
|
+
onChange={this.wrappedHandleTimeRangeFilterChange}
|
72
|
+
/>
|
73
|
+
</FormControl>
|
74
|
+
<Paper className="models-container" style={{marginTop: "8px"}}>
|
75
|
+
<Table className="models">
|
76
|
+
<TableHead>
|
77
|
+
<TableRow>
|
78
|
+
<SchedulableRecordTableCell>Status</SchedulableRecordTableCell>
|
79
|
+
<SchedulableRecordTableCell>ID</SchedulableRecordTableCell>
|
80
|
+
<SchedulableRecordTableCell>Cron</SchedulableRecordTableCell>
|
81
|
+
<SchedulableRecordTableCell>Next Execute At</SchedulableRecordTableCell>
|
82
|
+
<SchedulableRecordTableCell>Delay Sec</SchedulableRecordTableCell>
|
83
|
+
<SchedulableRecordTableCell>Execute Lock</SchedulableRecordTableCell>
|
84
|
+
<SchedulableRecordTableCell>Time To Unlock</SchedulableRecordTableCell>
|
85
|
+
<SchedulableRecordTableCell>Last Executed At</SchedulableRecordTableCell>
|
86
|
+
<SchedulableRecordTableCell>Locked By</SchedulableRecordTableCell>
|
87
|
+
<SchedulableRecordTableCell>Last Error Time</SchedulableRecordTableCell>
|
88
|
+
<SchedulableRecordTableCell>Retry Count</SchedulableRecordTableCell>
|
89
|
+
<SchedulableRecordTableCell>Detail</SchedulableRecordTableCell>
|
90
|
+
<SchedulableRecordTableCell>Ops</SchedulableRecordTableCell>
|
91
|
+
</TableRow>
|
92
|
+
</TableHead>
|
93
|
+
<TableBody>
|
94
|
+
{this.state.records.map((record) => (
|
95
|
+
<SchedulableRecord key={record.id} model_name={this.props.model_name} record={record} />
|
96
|
+
))}
|
97
|
+
</TableBody>
|
98
|
+
</Table>
|
99
|
+
</Paper>
|
100
|
+
</div>
|
101
|
+
)
|
102
|
+
}
|
103
|
+
|
104
|
+
private wrappedHandleTimeRangeFilterChange = (event: any) => {
|
105
|
+
event.persist();
|
106
|
+
this.handleTimeRangeFilterChange(event);
|
107
|
+
}
|
108
|
+
}
|
109
|
+
|
110
|
+
export default SchedulableRecords;
|
@@ -0,0 +1,21 @@
|
|
1
|
+
import TableCell from '@material-ui/core/TableCell';
|
2
|
+
import TableRow from '@material-ui/core/TableRow';
|
3
|
+
import * as React from 'react';
|
4
|
+
|
5
|
+
import { ISignalProps } from './interfaces';
|
6
|
+
|
7
|
+
class Signal extends React.Component<ISignalProps, any> {
|
8
|
+
public render() {
|
9
|
+
const signal = this.props.signal;
|
10
|
+
return (
|
11
|
+
<TableRow>
|
12
|
+
<TableCell>{signal.worker_id}</TableCell>
|
13
|
+
<TableCell>{signal.signal}</TableCell>
|
14
|
+
<TableCell>{signal.sent_at}</TableCell>
|
15
|
+
<TableCell>{signal.received_at}</TableCell>
|
16
|
+
</TableRow>
|
17
|
+
)
|
18
|
+
}
|
19
|
+
}
|
20
|
+
|
21
|
+
export default Signal;
|
@@ -0,0 +1,74 @@
|
|
1
|
+
import Paper from '@material-ui/core/Paper';
|
2
|
+
import Table from '@material-ui/core/Table';
|
3
|
+
import TableBody from '@material-ui/core/TableBody';
|
4
|
+
import TableCell from '@material-ui/core/TableCell';
|
5
|
+
import TableHead from '@material-ui/core/TableHead';
|
6
|
+
import TableRow from '@material-ui/core/TableRow';
|
7
|
+
import * as React from 'react';
|
8
|
+
|
9
|
+
import { IGlobalWindow, ISignalsState } from './interfaces';
|
10
|
+
import Signal from './Signal';
|
11
|
+
|
12
|
+
declare var window: IGlobalWindow;
|
13
|
+
|
14
|
+
class Signals extends React.Component<any, ISignalsState> {
|
15
|
+
private fetchLoop: any;
|
16
|
+
|
17
|
+
constructor(props: any) {
|
18
|
+
super(props)
|
19
|
+
this.state = {records: []}
|
20
|
+
}
|
21
|
+
|
22
|
+
public componentDidMount() {
|
23
|
+
this.fetchSignals();
|
24
|
+
this.setFetchSignalLoop();
|
25
|
+
}
|
26
|
+
|
27
|
+
public componentWillUnmount() {
|
28
|
+
if (this.fetchLoop) {
|
29
|
+
clearTimeout(this.fetchLoop);
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
public setFetchSignalLoop(): void {
|
34
|
+
this.fetchLoop = setTimeout(() => {
|
35
|
+
this.fetchSignals();
|
36
|
+
this.setFetchSignalLoop();
|
37
|
+
}, 3000);
|
38
|
+
}
|
39
|
+
|
40
|
+
public fetchSignals(): void {
|
41
|
+
const that = this;
|
42
|
+
fetch(`${window.mountPath}/signals.json`)
|
43
|
+
.then((res) => res.json())
|
44
|
+
.then((data) => {
|
45
|
+
that.setState(data);
|
46
|
+
}).catch((err) => {
|
47
|
+
console.error(err);
|
48
|
+
});
|
49
|
+
}
|
50
|
+
|
51
|
+
public render() {
|
52
|
+
return (
|
53
|
+
<Paper className="signals-container">
|
54
|
+
<Table className="signals">
|
55
|
+
<TableHead>
|
56
|
+
<TableRow>
|
57
|
+
<TableCell>Worker ID</TableCell>
|
58
|
+
<TableCell>Signal</TableCell>
|
59
|
+
<TableCell>Sent At</TableCell>
|
60
|
+
<TableCell>Received At</TableCell>
|
61
|
+
</TableRow>
|
62
|
+
</TableHead>
|
63
|
+
<TableBody>
|
64
|
+
{this.state.records.map((record) => {
|
65
|
+
return <Signal key={`${record.worker_id}-${record.sent_at}`} signal={record} />
|
66
|
+
})}
|
67
|
+
</TableBody>
|
68
|
+
</Table>
|
69
|
+
</Paper>
|
70
|
+
)
|
71
|
+
}
|
72
|
+
}
|
73
|
+
|
74
|
+
export default Signals;
|
@@ -0,0 +1,106 @@
|
|
1
|
+
import Button from '@material-ui/core/Button';
|
2
|
+
import Snackbar from '@material-ui/core/Snackbar';
|
3
|
+
import TableCell from '@material-ui/core/TableCell';
|
4
|
+
import TableRow from '@material-ui/core/TableRow';
|
5
|
+
import * as React from 'react';
|
6
|
+
|
7
|
+
import { IGlobalWindow, IWorkerProps } from "./interfaces";
|
8
|
+
|
9
|
+
declare var window: IGlobalWindow;
|
10
|
+
|
11
|
+
class Worker extends React.Component<IWorkerProps, any> {
|
12
|
+
constructor(props: IWorkerProps) {
|
13
|
+
super(props)
|
14
|
+
this.handleQuietClick = this.handleQuietClick.bind(this)
|
15
|
+
this.handleStopClick = this.handleStopClick.bind(this)
|
16
|
+
this.handleNotificationClose = this.handleNotificationClose.bind(this)
|
17
|
+
this.state = {
|
18
|
+
notificationMessage: <span />,
|
19
|
+
notificationOpen: false,
|
20
|
+
}
|
21
|
+
}
|
22
|
+
|
23
|
+
public render() {
|
24
|
+
const worker = this.props.worker;
|
25
|
+
return (
|
26
|
+
<TableRow>
|
27
|
+
<TableCell>{worker.worker_id}</TableCell>
|
28
|
+
<TableCell numeric={true}>{worker.max_thread_size}</TableCell>
|
29
|
+
<TableCell numeric={true}>{worker.current_queue_size}</TableCell>
|
30
|
+
<TableCell numeric={true}>{worker.current_executing_size}</TableCell>
|
31
|
+
<TableCell>{worker.executor_status}</TableCell>
|
32
|
+
<TableCell>{worker.polling_model_names}</TableCell>
|
33
|
+
<TableCell>{worker.last_heartbeated_at}</TableCell>
|
34
|
+
<TableCell>
|
35
|
+
<Button variant="contained" style={{"marginRight": "8px"}} onClick={this.handleQuietClick}>Quiet</Button>
|
36
|
+
<Button variant="contained" color="secondary" onClick={this.handleStopClick}>Stop</Button>
|
37
|
+
<Snackbar
|
38
|
+
anchorOrigin={{vertical: "bottom", horizontal: "right"}}
|
39
|
+
open={this.state.notificationOpen}
|
40
|
+
autoHideDuration={3000}
|
41
|
+
onClose={this.handleNotificationClose}
|
42
|
+
message={this.state.notificationMessage}
|
43
|
+
/>
|
44
|
+
</TableCell>
|
45
|
+
|
46
|
+
</TableRow>
|
47
|
+
)
|
48
|
+
}
|
49
|
+
|
50
|
+
private handleQuietClick(event: any) {
|
51
|
+
const worker = this.props.worker;
|
52
|
+
fetch(`${window.mountPath}/signals`, {
|
53
|
+
body: JSON.stringify({"worker_id": worker.worker_id, "signal": "TSTP"}),
|
54
|
+
headers: {"content-type": "application/json"},
|
55
|
+
method: "POST"
|
56
|
+
}).then(this.handleResponseStatus).then((res) => {
|
57
|
+
this.setState({
|
58
|
+
notificationMessage: <span>Quiet {worker.worker_id}</span>,
|
59
|
+
notificationOpen: true,
|
60
|
+
})
|
61
|
+
}).catch((err) => {
|
62
|
+
this.setState({
|
63
|
+
notificationMessage: <span>Failed to Quiet ({err.message})</span>,
|
64
|
+
notificationOpen: true,
|
65
|
+
})
|
66
|
+
})
|
67
|
+
}
|
68
|
+
|
69
|
+
private handleStopClick(event: any) {
|
70
|
+
const worker = this.props.worker;
|
71
|
+
fetch(`${window.mountPath}/signals`, {
|
72
|
+
body: JSON.stringify({"worker_id": worker.worker_id, "signal": "TERM"}),
|
73
|
+
headers: {"content-type": "application/json"},
|
74
|
+
method: "POST"
|
75
|
+
}).then(this.handleResponseStatus).then((res) => {
|
76
|
+
this.setState({
|
77
|
+
notificationMessage: <span>Stop {worker.worker_id}</span>,
|
78
|
+
notificationOpen: true,
|
79
|
+
})
|
80
|
+
}).catch((err) => {
|
81
|
+
this.setState({
|
82
|
+
notificationMessage: <span>Failed to Stop ({err.message})</span>,
|
83
|
+
notificationOpen: true,
|
84
|
+
})
|
85
|
+
})
|
86
|
+
}
|
87
|
+
|
88
|
+
private handleResponseStatus(res: Response): Promise<Response | Error> {
|
89
|
+
if (!res.ok) {
|
90
|
+
return res.json().then((data: any) => {
|
91
|
+
throw new Error(data.error);
|
92
|
+
})
|
93
|
+
} else {
|
94
|
+
return Promise.resolve(res);
|
95
|
+
}
|
96
|
+
}
|
97
|
+
|
98
|
+
private handleNotificationClose(ev: any, reason: any) {
|
99
|
+
this.setState({
|
100
|
+
...this.state,
|
101
|
+
notificationOpen: false,
|
102
|
+
})
|
103
|
+
}
|
104
|
+
}
|
105
|
+
|
106
|
+
export default Worker;
|
@@ -0,0 +1,78 @@
|
|
1
|
+
import Paper from '@material-ui/core/Paper';
|
2
|
+
import Table from '@material-ui/core/Table';
|
3
|
+
import TableBody from '@material-ui/core/TableBody';
|
4
|
+
import TableCell from '@material-ui/core/TableCell';
|
5
|
+
import TableHead from '@material-ui/core/TableHead';
|
6
|
+
import TableRow from '@material-ui/core/TableRow';
|
7
|
+
import * as React from 'react';
|
8
|
+
|
9
|
+
import { IGlobalWindow, IWorkersState } from "./interfaces";
|
10
|
+
import Worker from "./Worker";
|
11
|
+
|
12
|
+
declare var window: IGlobalWindow;
|
13
|
+
|
14
|
+
class Workers extends React.Component<any, IWorkersState> {
|
15
|
+
private fetchLoop: any;
|
16
|
+
|
17
|
+
constructor(props: any) {
|
18
|
+
super(props);
|
19
|
+
this.state = {records: []};
|
20
|
+
}
|
21
|
+
|
22
|
+
public componentDidMount() {
|
23
|
+
this.fetchWorkers();
|
24
|
+
this.setFetchWorkerLoop();
|
25
|
+
}
|
26
|
+
|
27
|
+
public componentWillUnmount() {
|
28
|
+
if (this.fetchLoop) {
|
29
|
+
clearTimeout(this.fetchLoop);
|
30
|
+
}
|
31
|
+
}
|
32
|
+
|
33
|
+
public setFetchWorkerLoop(): void {
|
34
|
+
this.fetchLoop = setTimeout(() => {
|
35
|
+
this.fetchWorkers();
|
36
|
+
this.setFetchWorkerLoop();
|
37
|
+
}, 3000);
|
38
|
+
}
|
39
|
+
|
40
|
+
public fetchWorkers(): void {
|
41
|
+
const that = this;
|
42
|
+
fetch(`${window.mountPath}/workers.json`)
|
43
|
+
.then((res) => res.json())
|
44
|
+
.then((data) => {
|
45
|
+
that.setState(data);
|
46
|
+
}).catch((err) => {
|
47
|
+
console.error(err);
|
48
|
+
});
|
49
|
+
}
|
50
|
+
|
51
|
+
public render() {
|
52
|
+
return (
|
53
|
+
<Paper className="workers-container">
|
54
|
+
<Table className="workers">
|
55
|
+
<TableHead>
|
56
|
+
<TableRow>
|
57
|
+
<TableCell>Worker ID</TableCell>
|
58
|
+
<TableCell numeric={true}>Thread</TableCell>
|
59
|
+
<TableCell numeric={true}>Internal Queue</TableCell>
|
60
|
+
<TableCell numeric={true}>Executing</TableCell>
|
61
|
+
<TableCell>Status</TableCell>
|
62
|
+
<TableCell>Polling Models</TableCell>
|
63
|
+
<TableCell>Last Heatbeated At</TableCell>
|
64
|
+
<TableCell> </TableCell>
|
65
|
+
</TableRow>
|
66
|
+
</TableHead>
|
67
|
+
<TableBody>
|
68
|
+
{this.state.records.map((record) => {
|
69
|
+
return <Worker key={record.worker_id} worker={record} />
|
70
|
+
})}
|
71
|
+
</TableBody>
|
72
|
+
</Table>
|
73
|
+
</Paper>
|
74
|
+
)
|
75
|
+
}
|
76
|
+
}
|
77
|
+
|
78
|
+
export default Workers;
|
@@ -0,0 +1,15 @@
|
|
1
|
+
import * as React from 'react';
|
2
|
+
import * as ReactDOM from 'react-dom';
|
3
|
+
import { BrowserRouter as Router } from "react-router-dom";
|
4
|
+
import App from './App';
|
5
|
+
import './index.css';
|
6
|
+
import { IGlobalWindow } from './interfaces';
|
7
|
+
|
8
|
+
declare var window: IGlobalWindow
|
9
|
+
|
10
|
+
ReactDOM.render(
|
11
|
+
<Router basename={window.mountPath || "/"}>
|
12
|
+
<App />
|
13
|
+
</Router>
|
14
|
+
, document.getElementById('root') as HTMLElement
|
15
|
+
);
|
@@ -0,0 +1,77 @@
|
|
1
|
+
interface IGlobalWindow {
|
2
|
+
mountPath: string
|
3
|
+
}
|
4
|
+
|
5
|
+
interface IWorkerRecord {
|
6
|
+
worker_id: string,
|
7
|
+
max_thread_size: number,
|
8
|
+
current_queue_size: number,
|
9
|
+
current_executing_size: number,
|
10
|
+
polling_model_names: string[],
|
11
|
+
executor_status: string,
|
12
|
+
last_heartbeated_at: string,
|
13
|
+
}
|
14
|
+
interface IWorkersState {
|
15
|
+
records: IWorkerRecord[]
|
16
|
+
}
|
17
|
+
interface IWorkerProps {
|
18
|
+
worker: IWorkerRecord
|
19
|
+
}
|
20
|
+
|
21
|
+
interface ISignalRecord {
|
22
|
+
worker_id: string,
|
23
|
+
signal: string,
|
24
|
+
sent_at: string,
|
25
|
+
received_at: string,
|
26
|
+
}
|
27
|
+
interface ISignalsState {
|
28
|
+
records: ISignalRecord[]
|
29
|
+
}
|
30
|
+
interface ISignalProps {
|
31
|
+
signal: ISignalRecord
|
32
|
+
}
|
33
|
+
|
34
|
+
interface ISchedulableRecord {
|
35
|
+
crono_trigger_status: string,
|
36
|
+
id: number,
|
37
|
+
cron: string | null,
|
38
|
+
next_execute_at: string | null,
|
39
|
+
last_executed_at: string | null,
|
40
|
+
timezone: string | null,
|
41
|
+
execute_lock: number,
|
42
|
+
locked_by: string | null,
|
43
|
+
started_at: string,
|
44
|
+
finished_at: string,
|
45
|
+
last_error_name: string,
|
46
|
+
last_error_reason: string,
|
47
|
+
last_error_time: string,
|
48
|
+
retry_count: number,
|
49
|
+
time_to_unlock: number,
|
50
|
+
delay_sec: number,
|
51
|
+
}
|
52
|
+
interface ISchedulableRecordsProps {
|
53
|
+
model_name: string
|
54
|
+
}
|
55
|
+
interface ISchedulableRecordsStates {
|
56
|
+
records: ISchedulableRecord[],
|
57
|
+
timeRangeMinute: number,
|
58
|
+
}
|
59
|
+
|
60
|
+
interface ISchedulableRecordProps {
|
61
|
+
model_name: string,
|
62
|
+
record: ISchedulableRecord
|
63
|
+
}
|
64
|
+
|
65
|
+
export {
|
66
|
+
IGlobalWindow,
|
67
|
+
IWorkerRecord,
|
68
|
+
IWorkersState,
|
69
|
+
IWorkerProps,
|
70
|
+
ISignalRecord,
|
71
|
+
ISignalsState,
|
72
|
+
ISignalProps,
|
73
|
+
ISchedulableRecord,
|
74
|
+
ISchedulableRecordsProps,
|
75
|
+
ISchedulableRecordsStates,
|
76
|
+
ISchedulableRecordProps
|
77
|
+
}
|