@Override public Trigger byTime(String cronExpression) { return new TimeTrigger(cronExpression); }
@Override public List<TriggerInfo> getTriggerInfos(TriggerInfoContext context) { for (Notification notification : context.getNotifications()) { if (!isSatisfied(context.getSchedule(), notification)) { continue; } Long logicalStartTime = getLogicalStartTime(notification); if (logicalStartTime == null) { LOG.warn("The notification '{}' in the job of schedule '{}' does not contain logical start time", notification, context.getSchedule()); continue; } TriggerInfo triggerInfo = new DefaultTimeTriggerInfo(getCronExpression(), logicalStartTime); return Collections.singletonList(triggerInfo); } return Collections.emptyList(); }
public TimeTrigger(String cronExpression) { super(cronExpression); validate(); }
private void testUpdateSchedule(ApplicationId appV2Id) throws Exception { ScheduleDetail updateDetail = new ScheduleDetail(AppWithSchedule.SCHEDULE, "updatedDescription", null, ImmutableMap.of("twoKey", "twoValue", "someKey", "newValue"), new TimeTrigger("0 4 * * *"), ImmutableList.of(new ConcurrencyConstraint(5)), null); new TimeTrigger("0 4 * * *"), ImmutableList.of(new ConcurrencyConstraint(5)), null); response = updateSchedule(TEST_NAMESPACE1, AppWithSchedule.NAME, null, Assert.assertEquals("0 4 * * *", ((TimeTrigger) schedule.getTrigger()).getCronExpression()); Assert.assertEquals(new ProtoConstraint.ConcurrencyConstraint(5), schedule.getConstraints().get(0)); Assert.assertEquals("0/15 * * * * ?", ((TimeTrigger) schedule.getTrigger()).getCronExpression());
/** * Checks if the given notification satisfies this trigger. */ private boolean isSatisfied(ProgramSchedule schedule, Notification notification) { if (!notification.getNotificationType().equals(Notification.Type.TIME)) { return false; } String systemOverridesJson = notification.getProperties().get(ProgramOptionConstants.SYSTEM_OVERRIDES); if (systemOverridesJson == null) { return false; } Map<String, String> args = GSON.fromJson(systemOverridesJson, STRING_STRING_MAP); String cronExpr = args.get(ProgramOptionConstants.CRON_EXPRESSION); // See if the notification is from pre 4.3 system, which doesn't have the cron expression in the notification. // The checking is done by the fact that in pre 4.3 system, composite trigger is not supported, // hence if there is a time notification, it must be matching with this trigger. return getCronExpression().equals(cronExpr) || (cronExpr == null && schedule.getTrigger().getType() == Type.TIME); } }
@Override public boolean isSatisfied(ProgramSchedule schedule, List<Notification> notifications) { for (Notification notification : notifications) { if (isSatisfied(schedule, notification)) { return true; } } return false; }
/** * Checks if the given notification satisfies this trigger. */ private boolean isSatisfied(ProgramSchedule schedule, Notification notification) { if (!notification.getNotificationType().equals(Notification.Type.TIME)) { return false; } String systemOverridesJson = notification.getProperties().get(ProgramOptionConstants.SYSTEM_OVERRIDES); if (systemOverridesJson == null) { return false; } Map<String, String> args = GSON.fromJson(systemOverridesJson, STRING_STRING_MAP); String cronExpr = args.get(ProgramOptionConstants.CRON_EXPRESSION); // See if the notification is from pre 4.3 system, which doesn't have the cron expression in the notification. // The checking is done by the fact that in pre 4.3 system, composite trigger is not supported, // hence if there is a time notification, it must be matching with this trigger. return getCronExpression().equals(cronExpr) || (cronExpr == null && schedule.getTrigger().getType() == Type.TIME); } }
@Override public boolean isSatisfied(ProgramSchedule schedule, List<Notification> notifications) { for (Notification notification : notifications) { if (isSatisfied(schedule, notification)) { return true; } } return false; }
@Override public Trigger byTime(String cronExpression) { return new TimeTrigger(cronExpression); }
@Override public List<TriggerInfo> getTriggerInfos(TriggerInfoContext context) { for (Notification notification : context.getNotifications()) { if (!isSatisfied(context.getSchedule(), notification)) { continue; } Long logicalStartTime = getLogicalStartTime(notification); if (logicalStartTime == null) { LOG.warn("The notification '{}' in the job of schedule '{}' does not contain logical start time", notification, context.getSchedule()); continue; } TriggerInfo triggerInfo = new DefaultTimeTriggerInfo(getCronExpression(), logicalStartTime); return Collections.singletonList(triggerInfo); } return Collections.emptyList(); }
String cron = ((TimeTrigger) timeTrigger).getCronExpression(); String triggerName = AbstractTimeSchedulerService.getTriggerName(program, programType, schedule.getName(), cron); cronTriggerKeyMap.put(((TimeTrigger) schedule.getTrigger()).getCronExpression(), triggerKeyForName(triggerName)); return cronTriggerKeyMap;
@Override public void updateLaunchArguments(ProgramSchedule schedule, List<Notification> notifications, Map<String, String> systemArgs, Map<String, String> userArgs) { for (Notification notification : notifications) { if (!isSatisfied(schedule, notification)) { continue; } String systemOverridesJson = notification.getProperties().get(ProgramOptionConstants.SYSTEM_OVERRIDES); String userOverridesJson = notification.getProperties().get(ProgramOptionConstants.USER_OVERRIDES); if (userOverridesJson == null || systemOverridesJson == null) { // Ignore the malformed notification continue; } systemArgs.putAll(GSON.<Map<String, String>>fromJson(systemOverridesJson, STRING_STRING_MAP)); userArgs.putAll(GSON.<Map<String, String>>fromJson(userOverridesJson, STRING_STRING_MAP)); return; } }
public TimeTrigger(String cronExpression) { super(cronExpression); validate(); }
/** * Adds and enables time based schedules for the given workflow at the given frequency. * * @param scheduleMins the number of minutes to wait before launching the given workflow each time * @param workflowId the ID of the scheduled workflow */ private ProgramSchedule initializeSchedules(int scheduleMins, WorkflowId workflowId) throws ConflictException, BadRequestException, NotFoundException { ProgramSchedule schedule = new ProgramSchedule(String.format("%dMinSchedule", scheduleMins), "time schedule", workflowId, Collections.emptyMap(), new TimeTrigger(String.format("*/%d * * * *", scheduleMins)), Collections.emptyList()); scheduler.addSchedule(schedule); scheduler.enableSchedule(schedule.getScheduleId()); return schedule; }
String cron = ((TimeTrigger) timeTrigger).getCronExpression(); String triggerName = AbstractTimeSchedulerService.getTriggerName(program, programType, schedule.getName(), cron); cronTriggerKeyMap.put(((TimeTrigger) schedule.getTrigger()).getCronExpression(), triggerKeyForName(triggerName)); return cronTriggerKeyMap;
@Override public void updateLaunchArguments(ProgramSchedule schedule, List<Notification> notifications, Map<String, String> systemArgs, Map<String, String> userArgs) { for (Notification notification : notifications) { if (!isSatisfied(schedule, notification)) { continue; } String systemOverridesJson = notification.getProperties().get(ProgramOptionConstants.SYSTEM_OVERRIDES); String userOverridesJson = notification.getProperties().get(ProgramOptionConstants.USER_OVERRIDES); if (userOverridesJson == null || systemOverridesJson == null) { // Ignore the malformed notification continue; } systemArgs.putAll(GSON.<Map<String, String>>fromJson(systemOverridesJson, STRING_STRING_MAP)); userArgs.putAll(GSON.<Map<String, String>>fromJson(userOverridesJson, STRING_STRING_MAP)); return; } }
@Test public void testNextSchedule() throws Exception { // a schedule to be triggered every 5 minutes ProgramSchedule sched = new ProgramSchedule("tsched11", "two times schedule", PROG1_ID, ImmutableMap.of("prop2", "xx"), new TimeTrigger("*/5 * * * *"), Collections.emptyList()); timeScheduler.addProgramSchedule(sched); // schedule is by default SUSPENDED after being added, resume it to enable the schedule timeScheduler.resumeProgramSchedule(sched); long currentTimeInSeconds = TimeUnit.MILLISECONDS.toSeconds(System.currentTimeMillis()); long startTimeInSeconds = currentTimeInSeconds + TimeUnit.HOURS.toSeconds(1); long endTimeInSeconds = currentTimeInSeconds + TimeUnit.HOURS.toSeconds(3); List<ScheduledRuntime> nextRuntimes = timeScheduler.getAllScheduledRunTimes(PROG1_ID, SchedulableProgramType.WORKFLOW, startTimeInSeconds, endTimeInSeconds); // for a scan range of 1pm to 3pm. since start time is inclusive, from 1pm tp 2pm we will have 13 schedules // and from 2:05 pm to 2:55pm will have 11 schedules as end time is exclusive. in total we expect 24 schedules. Assert.assertEquals(24, nextRuntimes.size()); } }
@Test public void testAddDeleteScheduleWithProfileProperty() throws Exception { // put my profile and by default it is enabled ProfileId profileId = NS_ID.profile("MyProfile"); putProfile(profileId, Profile.NATIVE, 200); // add a schedule, it should succeed since the profile is enabled. ProgramSchedule tsched1 = new ProgramSchedule("tsched1", "one time schedule", PROG1_ID, ImmutableMap.of("prop1", "nn", SystemArguments.PROFILE_NAME, profileId.getScopedName()), new TimeTrigger("* * ? * 1"), ImmutableList.<Constraint>of()); scheduler.addSchedule(tsched1); // now disable the profile and delete, deletion should fail because the profile is now associated with the schedule disableProfile(profileId, 200); deleteProfile(profileId, 409); // delete it scheduler.deleteSchedule(TSCHED1_ID); // now deletion should succeed since it should remove assignment from the profile deleteProfile(profileId, 200); }
@Test public void testAddScheduleWithDisabledProfile() throws Exception { // put my profile and by default it is enabled ProfileId profileId = NS_ID.profile("MyProfile"); Profile profile = new Profile("MyProfile", Profile.NATIVE.getLabel(), Profile.NATIVE.getDescription(), Profile.NATIVE.getScope(), Profile.NATIVE.getProvisioner()); putProfile(profileId, profile, 200); // add a schedule, it should succeed since the profile is enabled. ProgramSchedule tsched1 = new ProgramSchedule("tsched1", "one time schedule", PROG1_ID, ImmutableMap.of("prop1", "nn", SystemArguments.PROFILE_NAME, "USER:MyProfile"), new TimeTrigger("* * ? * 1"), ImmutableList.<Constraint>of()); scheduler.addSchedule(tsched1); Assert.assertEquals(Collections.singletonList(tsched1), scheduler.listSchedules(PROG1_ID)); // now disable the profile disableProfile(profileId, 200); // delete it scheduler.deleteSchedule(TSCHED1_ID); Assert.assertEquals(Collections.emptyList(), scheduler.listSchedules(PROG1_ID)); // add it again should also fail since the profile is disabled try { scheduler.addSchedule(tsched1); Assert.fail(); } catch (ProfileConflictException e) { // expected } // clean up deleteProfile(profileId, 200); }
Collections.emptyMap(), new PartitionTrigger(DS1_ID, 1), Collections.emptyList()); final ProgramSchedule sched2 = new ProgramSchedule("sched2", "time schedule", PROG2_ID, Collections.emptyMap(), new TimeTrigger("* * * 1 1"), Collections.emptyList()); final ProgramSchedule sched3 = new ProgramSchedule("sched3", "two partitions schedule", PROG4_ID, Collections.emptyMap(), new PartitionTrigger(DS1_ID, 2), Collections.emptyList()); final ProgramSchedule sched4 = new ProgramSchedule("sched4", "time schedule", PROG5_ID, Collections.emptyMap(), new TimeTrigger("* * * 2 1"), Collections.emptyList());