-
Notifications
You must be signed in to change notification settings - Fork 2.6k
FINERACT-2493: New command processing - job scheduling #5903
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -49,6 +49,7 @@ | |
| import java.util.Objects; | ||
| import lombok.RequiredArgsConstructor; | ||
| import org.apache.commons.lang3.StringUtils; | ||
| import org.apache.fineract.command.core.CommandDispatcher; | ||
| import org.apache.fineract.commands.domain.CommandWrapper; | ||
| import org.apache.fineract.commands.service.CommandWrapperBuilder; | ||
| import org.apache.fineract.commands.service.PortfolioCommandSourceWritePlatformService; | ||
|
|
@@ -62,8 +63,11 @@ | |
| import org.apache.fineract.infrastructure.core.serialization.ToApiJsonSerializer; | ||
| import org.apache.fineract.infrastructure.core.service.Page; | ||
| import org.apache.fineract.infrastructure.core.service.SearchParameters; | ||
| import org.apache.fineract.infrastructure.jobs.command.JobUpdateCommand; | ||
| import org.apache.fineract.infrastructure.jobs.data.JobDetailData; | ||
| import org.apache.fineract.infrastructure.jobs.data.JobDetailHistoryData; | ||
| import org.apache.fineract.infrastructure.jobs.data.JobUpdateRequest; | ||
| import org.apache.fineract.infrastructure.jobs.data.JobUpdateResponse; | ||
| import org.apache.fineract.infrastructure.jobs.service.JobRegisterService; | ||
| import org.apache.fineract.infrastructure.jobs.service.SchedulerJobRunnerReadService; | ||
| import org.apache.fineract.infrastructure.security.exception.NoAuthorizationException; | ||
|
|
@@ -87,6 +91,7 @@ public class SchedulerJobApiResource { | |
| private final PlatformSecurityContext context; | ||
| private final FineractProperties fineractProperties; | ||
| private final SqlValidator sqlValidator; | ||
| private final CommandDispatcher dispatcher; | ||
|
|
||
| @GET | ||
| @Operation(summary = "Retrieve Scheduler Jobs", operationId = "retrieveAllSchedulerJobs", description = "Returns the list of jobs.\n" | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Looks like authorization enforcement is missing. In the legacy code these checks are usually done by using |
||
|
|
@@ -173,14 +178,14 @@ public Response executeJobByShortName( | |
| } | ||
|
|
||
| @PUT | ||
| @Path("{" + SchedulerJobApiConstants.JOB_ID + "}") | ||
| @Consumes({ MediaType.APPLICATION_JSON }) | ||
| @Path("{jobId}") | ||
| @Consumes(MediaType.APPLICATION_JSON) | ||
| @Operation(summary = "Update a Job", description = "Updates the details of a job.") | ||
| @RequestBody(required = true, content = @Content(schema = @Schema(implementation = SchedulerJobApiResourceSwagger.PutJobsJobIDRequest.class))) | ||
| @ApiResponse(responseCode = "200", description = "OK") | ||
| public String updateJobDetail(@PathParam(SchedulerJobApiConstants.JOB_ID) @Parameter(description = "jobId") final Long jobId, | ||
| @Parameter(hidden = true) final String jsonRequestBody) { | ||
| return updateJobDetail(IdTypeResolver.resolveDefault(), Objects.toString(jobId, null), jsonRequestBody); | ||
| public JobUpdateResponse updateJobDetail(@PathParam("jobId") Long jobId, JobUpdateRequest request) { | ||
| request.setJobId(jobId); | ||
| var command = new JobUpdateCommand(); | ||
| command.setPayload(request); | ||
| return dispatcher.<JobUpdateRequest, JobUpdateResponse>dispatch(command).get(); | ||
| } | ||
|
|
||
| @PUT | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,29 @@ | ||
| /** | ||
| * Licensed to the Apache Software Foundation (ASF) under one | ||
| * or more contributor license agreements. See the NOTICE file | ||
| * distributed with this work for additional information | ||
| * regarding copyright ownership. The ASF licenses this file | ||
| * to you under the Apache License, Version 2.0 (the | ||
| * "License"); you may not use this file except in compliance | ||
| * with the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, | ||
| * software distributed under the License is distributed on an | ||
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| * KIND, either express or implied. See the License for the | ||
| * specific language governing permissions and limitations | ||
| * under the License. | ||
| */ | ||
|
|
||
| package org.apache.fineract.infrastructure.jobs.command; | ||
|
|
||
| import lombok.Data; | ||
| import lombok.EqualsAndHashCode; | ||
| import org.apache.fineract.command.core.Command; | ||
| import org.apache.fineract.infrastructure.jobs.data.JobUpdateRequest; | ||
|
|
||
| @Data | ||
| @EqualsAndHashCode(callSuper = true) | ||
| public class JobUpdateCommand extends Command<JobUpdateRequest> {} |
This file was deleted.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| /** | ||
| * Licensed to the Apache Software Foundation (ASF) under one | ||
| * or more contributor license agreements. See the NOTICE file | ||
| * distributed with this work for additional information | ||
| * regarding copyright ownership. The ASF licenses this file | ||
| * to you under the Apache License, Version 2.0 (the | ||
| * "License"); you may not use this file except in compliance | ||
| * with the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, | ||
| * software distributed under the License is distributed on an | ||
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| * KIND, either express or implied. See the License for the | ||
| * specific language governing permissions and limitations | ||
| * under the License. | ||
| */ | ||
|
|
||
| package org.apache.fineract.infrastructure.jobs.data; | ||
|
|
||
| import com.fasterxml.jackson.annotation.JsonIgnore; | ||
| import jakarta.validation.constraints.AssertTrue; | ||
| import java.io.Serial; | ||
| import java.io.Serializable; | ||
| import lombok.AllArgsConstructor; | ||
| import lombok.Builder; | ||
| import lombok.Data; | ||
| import lombok.NoArgsConstructor; | ||
| import lombok.experimental.FieldNameConstants; | ||
| import org.quartz.CronExpression; | ||
|
|
||
| @Builder | ||
| @Data | ||
| @NoArgsConstructor | ||
| @AllArgsConstructor | ||
| @FieldNameConstants | ||
| public class JobUpdateRequest implements Serializable { | ||
|
|
||
| @Serial | ||
| private static final long serialVersionUID = 1L; | ||
|
|
||
| private Long jobId; | ||
|
|
||
| private String displayName; | ||
| private String cronExpression; | ||
| private Boolean active; | ||
|
|
||
| @JsonIgnore | ||
| @AssertTrue(message = "{org.apache.fineract.infrastructure.jobs.update.at-least-one-field}") | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok, two things:
This keeps things short and we have the same number of segments in both keys ("assertions" tells us already that something is validated, so we don't have to use words like "invalid" and similar). Not earth shattering differences, but keeps everything compact and concise.
|
||
| public boolean isAtLeastOneFieldPresent() { | ||
| return displayName != null || cronExpression != null || active != null; | ||
| } | ||
|
|
||
| @JsonIgnore | ||
| @AssertTrue(message = "{org.apache.fineract.infrastructure.jobs.cron-expression.invalid}") | ||
| public boolean isCronExpressionValid() { | ||
| return cronExpression == null || CronExpression.isValidExpression(cronExpression.trim()); | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,41 @@ | ||
| /** | ||
| * Licensed to the Apache Software Foundation (ASF) under one | ||
| * or more contributor license agreements. See the NOTICE file | ||
| * distributed with this work for additional information | ||
| * regarding copyright ownership. The ASF licenses this file | ||
| * to you under the Apache License, Version 2.0 (the | ||
| * "License"); you may not use this file except in compliance | ||
| * with the License. You may obtain a copy of the License at | ||
| * | ||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||
| * | ||
| * Unless required by applicable law or agreed to in writing, | ||
| * software distributed under the License is distributed on an | ||
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||
| * KIND, either express or implied. See the License for the | ||
| * specific language governing permissions and limitations | ||
| * under the License. | ||
| */ | ||
|
|
||
| package org.apache.fineract.infrastructure.jobs.data; | ||
|
|
||
| import java.io.Serial; | ||
| import java.io.Serializable; | ||
| import java.util.Map; | ||
| import lombok.AllArgsConstructor; | ||
| import lombok.Builder; | ||
| import lombok.Data; | ||
| import lombok.NoArgsConstructor; | ||
|
|
||
| @Builder | ||
| @Data | ||
| @NoArgsConstructor | ||
| @AllArgsConstructor | ||
| public class JobUpdateResponse implements Serializable { | ||
|
|
||
| @Serial | ||
| private static final long serialVersionUID = 1L; | ||
|
|
||
| private Long resourceId; // the jobId | ||
| private Map<String, Object> changes; // what actually changed — kept for backward compatibility | ||
| } |
| Original file line number | Diff line number | Diff line change | ||
|---|---|---|---|---|
| @@ -0,0 +1,60 @@ | ||||
| /** | ||||
| * Licensed to the Apache Software Foundation (ASF) under one | ||||
| * or more contributor license agreements. See the NOTICE file | ||||
| * distributed with this work for additional information | ||||
| * regarding copyright ownership. The ASF licenses this file | ||||
| * to you under the Apache License, Version 2.0 (the | ||||
| * "License"); you may not use this file except in compliance | ||||
| * with the License. You may obtain a copy of the License at | ||||
| * | ||||
| * http://www.apache.org/licenses/LICENSE-2.0 | ||||
| * | ||||
| * Unless required by applicable law or agreed to in writing, | ||||
| * software distributed under the License is distributed on an | ||||
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | ||||
| * KIND, either express or implied. See the License for the | ||||
| * specific language governing permissions and limitations | ||||
| * under the License. | ||||
| */ | ||||
|
|
||||
| package org.apache.fineract.infrastructure.jobs.handler; | ||||
|
|
||||
| import io.github.resilience4j.retry.annotation.Retry; | ||||
| import java.util.Map; | ||||
| import lombok.RequiredArgsConstructor; | ||||
| import lombok.extern.slf4j.Slf4j; | ||||
| import org.apache.fineract.command.core.Command; | ||||
| import org.apache.fineract.command.core.CommandHandler; | ||||
| import org.apache.fineract.infrastructure.jobs.data.JobUpdateRequest; | ||||
| import org.apache.fineract.infrastructure.jobs.data.JobUpdateResponse; | ||||
| import org.apache.fineract.infrastructure.jobs.service.JobRegisterService; | ||||
| import org.apache.fineract.infrastructure.jobs.service.SchedularWritePlatformService; | ||||
| import org.springframework.stereotype.Component; | ||||
| import org.springframework.transaction.annotation.Transactional; | ||||
|
|
||||
| @Slf4j | ||||
| @Component | ||||
| @RequiredArgsConstructor | ||||
| public class JobUpdateCommandHandler implements CommandHandler<JobUpdateRequest, JobUpdateResponse> { | ||||
|
|
||||
| private final SchedularWritePlatformService schedularWritePlatformService; | ||||
| private final JobRegisterService jobRegisterService; | ||||
|
|
||||
| @Retry(name = "commandJobUpdate", fallbackMethod = "fallback") | ||||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the resilience configuration for this is missing? Please have a look at this here to see how this works:
|
||||
| @Override | ||||
| @Transactional | ||||
| public JobUpdateResponse handle(Command<JobUpdateRequest> command) { | ||||
| JobUpdateResponse response = schedularWritePlatformService.updateJobDetail(command.getPayload()); | ||||
|
|
||||
| Map<String, Object> changes = response.getChanges(); | ||||
| if (changes != null && (changes.containsKey("cronExpression") || changes.containsKey("active"))) { | ||||
| jobRegisterService.rescheduleJob(command.getPayload().getJobId()); | ||||
| } | ||||
| return response; | ||||
| } | ||||
|
|
||||
| @Override | ||||
| public JobUpdateResponse fallback(Command<JobUpdateRequest> command, Throwable t) { | ||||
| return CommandHandler.super.fallback(command, t); | ||||
| } | ||||
| } | ||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this something that should reside in a service? Or is this validation like in Jakarta Validation of input parameters? SqlValidator is a very low level implementation detail that we shouldn't reveal in the REST layer... my 2 cents.