-
Notifications
You must be signed in to change notification settings - Fork 51
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Convert interval parameter to cron schedule for self serve replication (
#238) ## Summary <!--- HINT: Replace #nnn with corresponding Issue number, if you are fixing an existing issue --> This PR adds cron schedule to the replication config for the self serve replication API and converts the interval parameter to a cron schedule. Cron schedule is needed as an input for the replication job that performs the cross cluster data copy. The library `cronutils` is added to perform the cron expression generation. The interval parameter can be validated as `12H`, `1D`, `2D`, `3D` and the cron schedule is generated based on: - 12H schedule dictates replication should trigger every 12 hours - The cron schedule should have an X hour to start from midnight where X can range from 0-23 and Y minute where Y is in [0, 15, 30, 45]. E.g 12hours can lead to schedule “0 30 3/12 ? * * *” -> trigger at 3:30am and 3:30pm every day. - If interval is not provided, a daily replication schedule should be set up with daily schedules with X hour starting from midnight. - X is randomized from 0-23 and Y is randomized as a value of [0, 15, 30, 45] to spread out the cron and avoid job clusters around a time. Examples of: 12H: `0 15 23/12 ? * * *` 1D: `0 45 10 ? * * *` 2D: `0 30 8 ? * */2 *` 3D: `0 0 8 ? * */3 *` ## Changes - [x] Client-facing API Changes - [ ] Internal API Changes - [ ] Bug Fixes - [x] New Features - [ ] Performance Improvements - [ ] Code Style - [ ] Refactoring - [ ] Documentation - [ ] Tests For all the boxes checked, please include additional details of the changes made in this pull request. ## Testing Done <!--- Check any relevant boxes with "x" --> - [x] Manually Tested on local docker setup. Please include commands ran, and their output. - [x] Added new tests for the changes made. - [ ] Updated existing tests to reflect the changes made. - [ ] No tests added or updated. Please explain why. If unsure, please feel free to ask for help. - [ ] Some other form of testing like staging or soak time in production. Please explain. For all the boxes checked, include a detailed description of the testing done for the changes made in this pull request. Unit tests added to check that the cron schedule was created successfully. POST http://localhost:8000/v1/databases/u_tableowner/tables for a 1D schedule: ``` { "policies": { "sharingEnabled": "true", "replication": { "config": [ { "destination": "clusterA" } ] } } } ``` response: ``` "replication": { "config": [ { "destination": "clusterA", "interval": "1D", "cronSchedule": "0 0 10 ? * * *" } ] } ``` 12H schedule: ``` "replication": { "config": [ { "destination": "clusterA", "interval": "12H", "cronSchedule": "0 0 23/12 ? * * *" } ] } ``` # Additional Information - [ ] Breaking Changes - [ ] Deprecations - [ ] Large PR broken into smaller PRs, and PR plan linked in the description. For all the boxes checked, include additional details of the changes made in this pull request.
- Loading branch information
1 parent
b2bc32b
commit 9be2378
Showing
8 changed files
with
167 additions
and
19 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
75 changes: 75 additions & 0 deletions
75
...ces/tables/src/main/java/com/linkedin/openhouse/tables/utils/IntervalToCronConverter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,75 @@ | ||
package com.linkedin.openhouse.tables.utils; | ||
|
||
import com.cronutils.builder.CronBuilder; | ||
import com.cronutils.model.CronType; | ||
import com.cronutils.model.definition.CronDefinitionBuilder; | ||
import com.cronutils.model.field.expression.FieldExpressionFactory; | ||
import com.linkedin.openhouse.common.exception.RequestValidationFailureException; | ||
import com.linkedin.openhouse.tables.api.spec.v0.request.components.ReplicationConfig; | ||
import com.linkedin.openhouse.tables.api.spec.v0.request.components.TimePartitionSpec; | ||
import java.util.Random; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.springframework.stereotype.Component; | ||
|
||
/** Utility class for generating a cron schedule given an interval for which a job should run */ | ||
@Slf4j | ||
@Component | ||
public class IntervalToCronConverter { | ||
|
||
/** | ||
* Public api to generate a cron schedule for a {@link ReplicationConfig} based on a given | ||
* interval string in the form 12H, 1D, 2D, 3D. | ||
* | ||
* @param interval | ||
* @return schedule | ||
*/ | ||
public static String generateCronExpression(String interval) { | ||
if (interval == null || interval.isEmpty()) { | ||
String errorMessage = "Replication interval is null or empty"; | ||
log.error(errorMessage); | ||
throw new RequestValidationFailureException(errorMessage); | ||
} | ||
int count = Integer.parseInt(interval.substring(0, interval.length() - 1)); | ||
// Generating random hourly and minute intervals for the cron expression | ||
int hour = new Random().nextInt(24); | ||
int minute = new int[] {0, 15, 30, 45}[new Random().nextInt(4)]; | ||
|
||
String granularity = interval.substring(interval.length() - 1); | ||
String schedule; | ||
|
||
if (granularity.equals(TimePartitionSpec.Granularity.HOUR.getGranularity())) { | ||
schedule = generateHourlyCronExpression(hour, minute, count); | ||
} else { | ||
schedule = generateDailyCronExpression(hour, minute, count); | ||
} | ||
return schedule; | ||
} | ||
|
||
private static String generateDailyCronExpression(int hour, int minute, int dailyInterval) { | ||
return CronBuilder.cron(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ)) | ||
.withYear(FieldExpressionFactory.always()) | ||
.withDoM(FieldExpressionFactory.questionMark()) | ||
.withDoW(FieldExpressionFactory.every(dailyInterval)) | ||
.withMonth(FieldExpressionFactory.always()) | ||
.withHour(FieldExpressionFactory.on(hour)) | ||
.withMinute(FieldExpressionFactory.on(minute)) | ||
.withSecond(FieldExpressionFactory.on(0)) | ||
.instance() | ||
.asString(); | ||
} | ||
|
||
private static String generateHourlyCronExpression(int hour, int minute, int hourlyInterval) { | ||
return CronBuilder.cron(CronDefinitionBuilder.instanceDefinitionFor(CronType.QUARTZ)) | ||
.withYear(FieldExpressionFactory.always()) | ||
.withDoM(FieldExpressionFactory.questionMark()) | ||
.withDoW(FieldExpressionFactory.always()) | ||
.withMonth(FieldExpressionFactory.always()) | ||
.withHour(FieldExpressionFactory.every(hourlyInterval)) | ||
.withMinute(FieldExpressionFactory.on(minute)) | ||
.withSecond(FieldExpressionFactory.on(0)) | ||
.instance() | ||
.asString() | ||
.replace( | ||
String.format("*/%d", hourlyInterval), String.format("%d/%d", hour, hourlyInterval)); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters