use of io.cdap.cdap.proto.Notification in project cdap by caskdata.
the class TimeTrigger method getTriggerInfos.
@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();
}
use of io.cdap.cdap.proto.Notification in project cdap by caskdata.
the class CoreSchedulerServiceTest method testRunScheduledJobs.
@Test
@Category(XSlowTests.class)
public void testRunScheduledJobs() throws Exception {
CConfiguration cConf = getInjector().getInstance(CConfiguration.class);
dataEventTopic = NamespaceId.SYSTEM.topic(cConf.get(Constants.Dataset.DATA_EVENT_TOPIC));
// Deploy the app with version
Id.Artifact appArtifactId = Id.Artifact.from(Id.Namespace.DEFAULT, "appwithschedules", VERSION1);
addAppArtifact(appArtifactId, AppWithFrequentScheduledWorkflows.class);
AppRequest<? extends Config> appRequest = new AppRequest<>(new ArtifactSummary(appArtifactId.getName(), appArtifactId.getVersion().getVersion()));
deploy(APP_ID, appRequest);
// Resume the schedule because schedules are initialized as paused
enableSchedule(AppWithFrequentScheduledWorkflows.TEN_SECOND_SCHEDULE_1);
enableSchedule(AppWithFrequentScheduledWorkflows.TEN_SECOND_SCHEDULE_2);
enableSchedule(AppWithFrequentScheduledWorkflows.DATASET_PARTITION_SCHEDULE_1);
enableSchedule(AppWithFrequentScheduledWorkflows.DATASET_PARTITION_SCHEDULE_2);
for (int i = 0; i < 5; i++) {
testNewPartition(i + 1);
}
// Enable COMPOSITE_SCHEDULE before publishing events to DATASET_NAME2
enableSchedule(AppWithFrequentScheduledWorkflows.COMPOSITE_SCHEDULE);
// disable the two partition schedules, send them notifications (but they should not trigger)
int runs1 = getRuns(WORKFLOW_1, ProgramRunStatus.ALL);
int runs2 = getRuns(WORKFLOW_2, ProgramRunStatus.ALL);
disableSchedule(AppWithFrequentScheduledWorkflows.DATASET_PARTITION_SCHEDULE_1);
// ensure schedule 2 is disabled after schedule 1
Thread.sleep(BUFFER);
long disableBeforeTime = System.currentTimeMillis();
disableSchedule(AppWithFrequentScheduledWorkflows.DATASET_PARTITION_SCHEDULE_2);
long disableAfterTime = System.currentTimeMillis() + 1;
publishNotification(dataEventTopic, NamespaceId.DEFAULT, AppWithFrequentScheduledWorkflows.DATASET_NAME1);
long minPublishTime = System.currentTimeMillis();
publishNotification(dataEventTopic, NamespaceId.DEFAULT, AppWithFrequentScheduledWorkflows.DATASET_NAME2);
// This would make sure the subscriber has processed the data event
waitUntilProcessed(dataEventTopic, minPublishTime);
// Both workflows must run at least once.
// If the testNewPartition() loop took longer than expected, it may be more (quartz fired multiple times)
Tasks.waitFor(true, () -> getRuns(SCHEDULED_WORKFLOW_1, ProgramRunStatus.COMPLETED) > 0 && getRuns(SCHEDULED_WORKFLOW_2, ProgramRunStatus.COMPLETED) > 0, 10, TimeUnit.SECONDS);
// There shouldn't be any partition trigger in the job queue
Assert.assertFalse(Iterables.any(getAllJobs(), job -> job.getSchedule().getTrigger() instanceof ProtoTrigger.PartitionTrigger));
ProgramId compositeWorkflow = APP_ID.workflow(AppWithFrequentScheduledWorkflows.COMPOSITE_WORKFLOW);
// Workflow scheduled with the composite trigger has never been started
Assert.assertEquals(0, getRuns(compositeWorkflow, ProgramRunStatus.ALL));
// Publish two more new partition notifications to satisfy the partition trigger in the composite trigger,
// and thus the whole composite trigger will be satisfied
publishNotification(dataEventTopic, NamespaceId.DEFAULT, AppWithFrequentScheduledWorkflows.DATASET_NAME2);
minPublishTime = System.currentTimeMillis();
publishNotification(dataEventTopic, NamespaceId.DEFAULT, AppWithFrequentScheduledWorkflows.DATASET_NAME2);
// This would make sure the subscriber has processed the data event
waitUntilProcessed(dataEventTopic, minPublishTime);
// Wait for 1 run to complete for compositeWorkflow
waitForCompleteRuns(1, compositeWorkflow);
for (RunRecordDetail runRecordMeta : store.getRuns(SCHEDULED_WORKFLOW_1, ProgramRunStatus.ALL, 0, Long.MAX_VALUE, Integer.MAX_VALUE).values()) {
Map<String, String> sysArgs = runRecordMeta.getSystemArgs();
Assert.assertNotNull(sysArgs);
TriggeringScheduleInfo scheduleInfo = GSON.fromJson(sysArgs.get(ProgramOptionConstants.TRIGGERING_SCHEDULE_INFO), TriggeringScheduleInfo.class);
Assert.assertEquals(AppWithFrequentScheduledWorkflows.TEN_SECOND_SCHEDULE_1, scheduleInfo.getName());
List<TriggerInfo> triggerInfos = scheduleInfo.getTriggerInfos();
// Only one notification is enough to satisfy Time Trigger
Assert.assertEquals(1, triggerInfos.size());
Assert.assertEquals(TriggerInfo.Type.TIME, triggerInfos.get(0).getType());
}
// Also verify that the two partition schedules did not trigger
Assert.assertEquals(runs1, getRuns(WORKFLOW_1, ProgramRunStatus.ALL));
Assert.assertEquals(runs2, getRuns(WORKFLOW_2, ProgramRunStatus.ALL));
// enable partition schedule 2 and test reEnableSchedules
scheduler.reEnableSchedules(NamespaceId.DEFAULT, disableBeforeTime, disableAfterTime);
Assert.assertEquals(ProgramScheduleStatus.SCHEDULED, scheduler.getScheduleStatus(APP_ID.schedule(AppWithFrequentScheduledWorkflows.DATASET_PARTITION_SCHEDULE_2)));
Assert.assertEquals(ProgramScheduleStatus.SUSPENDED, scheduler.getScheduleStatus(APP_ID.schedule(AppWithFrequentScheduledWorkflows.DATASET_PARTITION_SCHEDULE_1)));
testScheduleUpdate("disable");
testScheduleUpdate("update");
testScheduleUpdate("delete");
}
use of io.cdap.cdap.proto.Notification in project cdap by caskdata.
the class ScheduleTaskPublisher method publishNotification.
/**
* Publish notification for the triggered schedule
* @param notificationType type of the notification
* @param scheduleId {@link ScheduleId} of the triggered schedule
* @param systemOverrides Arguments that would be supplied as system runtime arguments for the program.
* @param userOverrides Arguments to add to the user runtime arguments for the program.
*/
public void publishNotification(Notification.Type notificationType, ScheduleId scheduleId, Map<String, String> systemOverrides, Map<String, String> userOverrides) throws Exception {
Map<String, String> properties = new HashMap<>();
properties.put(ProgramOptionConstants.SCHEDULE_ID, GSON.toJson(scheduleId));
properties.put(ProgramOptionConstants.SYSTEM_OVERRIDES, GSON.toJson(systemOverrides));
properties.put(ProgramOptionConstants.USER_OVERRIDES, GSON.toJson(userOverrides));
Notification notification = new Notification(notificationType, properties);
messagingService.publish(StoreRequestBuilder.of(topicId).addPayload(GSON.toJson(notification)).build());
}
use of io.cdap.cdap.proto.Notification in project cdap by caskdata.
the class RuntimeProgramStatusSubscriberService method processMessages.
@Override
protected void processMessages(StructuredTableContext context, Iterator<ImmutablePair<String, Notification>> messages) throws Exception {
while (messages.hasNext()) {
ImmutablePair<String, Notification> pair = messages.next();
Notification notification = pair.getSecond();
if (notification.getNotificationType() != Notification.Type.PROGRAM_STATUS) {
continue;
}
processNotification(pair.getFirst().getBytes(StandardCharsets.UTF_8), notification, getAppMetadataStore(context));
}
}
use of io.cdap.cdap.proto.Notification in project cdap by caskdata.
the class ProgramStatusTrigger method getTriggerSatisfiedResult.
/**
* Helper method to return a result from the given supplier if the trigger is satisfied with the given notifications,
* or return the default result if the trigger is not satisfied.
*
* @param notifications notifications used to determine whether the trigger is satisfied
* @param defaultResult the default result to return if the trigger is not satisfied
* @param function the function to get result from if the trigger is satisfied
* @param <T> type of the result to be returned
* @return a result of type T
*/
private <T> T getTriggerSatisfiedResult(List<Notification> notifications, T defaultResult, Function<ProgramRunInfo, T> function) {
for (Notification notification : notifications) {
if (!Notification.Type.PROGRAM_STATUS.equals(notification.getNotificationType())) {
continue;
}
String programRunIdString = notification.getProperties().get(ProgramOptionConstants.PROGRAM_RUN_ID);
String programRunStatusString = notification.getProperties().get(ProgramOptionConstants.PROGRAM_STATUS);
// Ignore notifications which specify an invalid programRunId or programStatus
if (programRunIdString == null || programRunStatusString == null) {
continue;
}
ProgramStatus programStatus;
try {
programStatus = ProgramRunStatus.toProgramStatus(ProgramRunStatus.valueOf(programRunStatusString));
} catch (IllegalArgumentException e) {
// Return silently, this happens for statuses that are not meant to be scheduled
continue;
}
ProgramRunId programRunId = GSON.fromJson(programRunIdString, ProgramRunId.class);
ProgramId triggeringProgramId = programRunId.getParent();
if (this.programId.equals(triggeringProgramId) && programStatuses.contains(programStatus)) {
return function.apply(new ProgramRunInfo(programStatus, programRunId));
}
}
return defaultResult;
}
Aggregations