Skip to content

Commit

Permalink
fix : 스케줄러 크론 검증 추가
Browse files Browse the repository at this point in the history
  • Loading branch information
Gyaak committed Aug 30, 2024
1 parent 663bb88 commit e5f40cf
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
import org.springframework.web.bind.annotation.RestController;

import com.talkka.server.admin.dto.SchedulerReqDto;
import com.talkka.server.admin.exception.InvalidCronExpressionException;
import com.talkka.server.admin.exception.SchedulerNotFoundException;
import com.talkka.server.admin.scheduler.DynamicSchedulingConfig;

Expand All @@ -29,7 +30,7 @@ public class SchedulerController {
public ResponseEntity<?> updateScheduler(@RequestBody SchedulerReqDto dto) {
try {
dynamicSchedulingConfig.updateCronExpression(dto);
} catch (SchedulerNotFoundException exception) {
} catch (SchedulerNotFoundException | InvalidCronExpressionException exception) {
log.error(exception.getMessage());
return ResponseEntity.badRequest().body(exception.getMessage());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package com.talkka.server.admin.exception;

public class InvalidCronExpressionException extends RuntimeException {
private static final String MESSAGE = "잘못된 크론 표현식입니다";

public InvalidCronExpressionException(String cron) {
super(MESSAGE + " : " + cron);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import java.util.List;
import java.util.Map;
import java.util.concurrent.ScheduledFuture;
import java.util.regex.Pattern;

import org.springframework.context.ApplicationContext;
import org.springframework.scheduling.annotation.EnableScheduling;
Expand All @@ -19,6 +20,7 @@

import com.talkka.server.admin.dto.SchedulerReqDto;
import com.talkka.server.admin.dto.SchedulerRespDto;
import com.talkka.server.admin.exception.InvalidCronExpressionException;
import com.talkka.server.admin.exception.SchedulerNotFoundException;

import jakarta.annotation.PostConstruct;
Expand All @@ -35,9 +37,10 @@ public class DynamicSchedulingConfig {
private final Map<String, Runnable> taskMap = new HashMap<>();
private final MultiValueMap<String, ScheduledFuture<?>> scheduledTasks = new LinkedMultiValueMap<>();
private final MultiValueMap<String, String> cronMap = new LinkedMultiValueMap<>();
private static final String CRON_REGEX = "^([0-5]?\\d|\\*|\\*/\\d+|\\d+-\\d+|\\d+,\\d+)(\\s+([0-5]?\\d|\\*|\\*/\\d+|\\d+-\\d+|\\d+,\\d+)){4}(\\s+([0-7]|\\*|\\*/\\d+|\\d+-\\d+|\\d+,\\d+|\\?))?$";

@PostConstruct
public void init() {
public void init() throws InvalidCronExpressionException {
registrar = new ScheduledTaskRegistrar();
ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
taskScheduler.setPoolSize(20);
Expand All @@ -60,8 +63,11 @@ public void init() {
Runnable task = () -> ReflectionUtils.invokeMethod(method, bean);
taskMap.put(name, task);

for (String cron : crons) {
cron.trim();
for (String c : crons) {
final String cron = c.trim();
if (!validateCronExpression(cron)) {
throw new InvalidCronExpressionException(cron);
}
ScheduledFuture<?> future = registrar.getScheduler()
.schedule(task, triggerContext -> new CronTrigger(cron).nextExecution(triggerContext));
scheduledTasks.add(name, future);
Expand All @@ -80,19 +86,33 @@ public List<SchedulerRespDto> getSchedulers() {
return schedulers;
}

public void updateCronExpression(SchedulerReqDto dto) throws SchedulerNotFoundException {
public void updateCronExpression(SchedulerReqDto dto) throws
SchedulerNotFoundException,
InvalidCronExpressionException {
List<String> cronList = new ArrayList<>();
for (String c : dto.cronString().split("\\|")) {
String cron = c.trim();
if (!validateCronExpression(cron)) {
throw new InvalidCronExpressionException(cron);
}
cronList.add(cron);
}
// 현재 해당 메소드의 스케줄링 작업 전부 멈추고 맵에서 삭제
scheduledTasks.get(dto.name()).forEach(future -> future.cancel(false));
scheduledTasks.remove(dto.name());
cronMap.remove(dto.name());
// 해당 메소드 가져옴
Runnable task = taskMap.get(dto.name());
// 크론식마다 스케줄 작업 추가
for (String cron : dto.cronString().split("\\|")) {
cron.trim();
for (String cron : cronList) {
ScheduledFuture<?> future = registrar.getScheduler()
.schedule(task, triggerContext -> new CronTrigger(cron).nextExecution(triggerContext));
scheduledTasks.add(dto.name(), future);
cronMap.add(dto.name(), cron);
}
}

private boolean validateCronExpression(String cron) {
return Pattern.compile(CRON_REGEX).matcher(cron).matches();
}
}
4 changes: 3 additions & 1 deletion server/src/main/resources/templates/admin/scheduler.html
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,9 @@ <h1 class="text-center mb-4">Scheduler Management</h1>
cronInput.readOnly = true;
editBtn.textContent = 'Edit';
} else {
alert('Failed to update the scheduler. Please try again.');
return response.text().then(error => {
alert(error);
});
}
})
.catch(error => {
Expand Down

0 comments on commit e5f40cf

Please sign in to comment.