155 lines
No EOL
4.7 KiB
Dart
155 lines
No EOL
4.7 KiB
Dart
|
|
import 'dart:io';
|
|
|
|
import 'package:cron/cron.dart';
|
|
import 'package:dart_framework/data/isolate_data.dart';
|
|
import 'package:dart_framework/platform/isolate_manager.dart';
|
|
import 'package:dart_framework/utils/string_util.dart';
|
|
import 'package:dart_framework/utils/system_util.dart';
|
|
import 'package:file_hasher/file_hasher.dart';
|
|
import 'package:oto_cli/cli/commands/command_exe.dart';
|
|
import 'package:oto_cli/cli/commands/scheduler/scheduler_interval.dart';
|
|
import 'package:oto_cli/oto/application.dart';
|
|
import 'package:oto_cli/oto/commands/command.dart';
|
|
import 'package:oto_cli/oto/data/command_data.dart';
|
|
|
|
class IsolateScheduler extends IsolateBase {
|
|
late String schedulerPath;
|
|
late String logsPath;
|
|
late String alias;
|
|
late File file;
|
|
late File logFile;
|
|
int fileHash = 0;
|
|
|
|
bool logEnable = false;
|
|
bool notProgress = true;
|
|
bool cronClosed = true;
|
|
int? interval;
|
|
String? cronExpress;
|
|
late DataBuild build;
|
|
SchedulerInterval? schedulerInterval;
|
|
CommandExe commandExe = CommandExe();
|
|
|
|
Cron? cron;
|
|
int nextStartTime = 0;
|
|
|
|
IsolateScheduler(Map data) {
|
|
alias = data['alias'];
|
|
schedulerPath = data['root'];
|
|
logsPath = data['logs'];
|
|
file = File('$schedulerPath/$alias.yaml');
|
|
}
|
|
|
|
@override
|
|
void onReady(Object? initData) async {
|
|
while(true) {
|
|
await Future.delayed(Duration(seconds: 1));
|
|
|
|
if(file.existsSync()) {
|
|
var updated = false;
|
|
var hash = await FileHasher.hash(file);
|
|
if(hash != fileHash) {
|
|
updated = true;
|
|
fileHash = hash;
|
|
//파일 내용이 바뀔때 마다 새로 읽어 들임
|
|
var map = Application.getMapFromYamlA(await file.readAsString());
|
|
|
|
//============ Validate yaml format ============//
|
|
try {
|
|
build = DataBuild.fromJson(map!);
|
|
} on Exception {
|
|
onError('Failed to parse yaml file.');
|
|
return;
|
|
}
|
|
if(build.scheduler == null) {
|
|
onError('Scheduler entry does not exist within yaml.');
|
|
return;
|
|
}
|
|
|
|
var scheduler = build.scheduler!;
|
|
if(scheduler.cron == null && scheduler.interval == null) {
|
|
onError('A scheduler script must have either a cron entry or an interval entry.');
|
|
return;
|
|
}
|
|
|
|
if(scheduler.cron != null) {
|
|
try {
|
|
Schedule.parse(scheduler.cron!);
|
|
cronExpress = scheduler.cron!;
|
|
} on Error {
|
|
onError("Cron express '${build.scheduler!.cron}' is not a suitable format.");
|
|
return;
|
|
}
|
|
}
|
|
|
|
if(scheduler.interval != null) {
|
|
interval = scheduler.interval!;
|
|
}
|
|
|
|
logEnable = scheduler.enableLog == null ? false : scheduler.enableLog!;
|
|
|
|
schedulerInterval?.activate = false;
|
|
}
|
|
|
|
//============ execute cron/interval ============//
|
|
if(cronExpress != null) {
|
|
//Use cron
|
|
if(cronClosed) {
|
|
cronClosed = false;
|
|
cron = Cron();
|
|
cron!.schedule(Schedule.parse(cronExpress!), () async {
|
|
if(notProgress) {
|
|
await execute(build);
|
|
cronClosed = true;
|
|
await cron!.close();
|
|
}
|
|
});
|
|
}
|
|
} else {
|
|
//Use interval
|
|
if(updated) {
|
|
schedulerInterval = SchedulerInterval(interval!, build, execute);
|
|
}
|
|
}
|
|
} else {
|
|
//file이 없을시 종료
|
|
onError("The file '${file.path}' does not exist.");
|
|
if(cron != null) await cron?.close();
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
|
|
Future execute(DataBuild data) async {
|
|
send(IsoMessege('log', data: "Scheduler '$alias' has started."));
|
|
notProgress = false;
|
|
logFile = File('$logsPath/${alias}_${getDate()}_${getTime().replaceAll(':', '')}_[$pid].txt');
|
|
if(data.scheduler!.enableLog ?? false) {
|
|
log('Start process on pid [$pid]');
|
|
}
|
|
await commandExe.executeScheduler(data, logEnable, logFile.path);
|
|
notProgress = true;
|
|
send(IsoMessege('log', data: "Scheduler '$alias' is done."));
|
|
return simpleFuture;
|
|
}
|
|
|
|
void log(String message) {
|
|
logFile.writeAsStringSync('[${getDates()}] $message\n', mode: FileMode.append, flush: true);
|
|
}
|
|
|
|
void logError(Exception e, StackTrace stacktace) {
|
|
log('[${e.toString()}]\n${stacktace.toString()}');
|
|
}
|
|
|
|
void onErrorStacktrace(Exception e, StackTrace stacktrace) {
|
|
onError('$e\n$stacktrace');
|
|
}
|
|
|
|
void onError(String message) {
|
|
sendTerminated('error', message);
|
|
}
|
|
|
|
void sendTerminated(String type, String message) {
|
|
send(IsoMessege('terminated', data: {'type': type, 'message': message, 'alias': alias}));
|
|
}
|
|
} |