Skip to content

Commit

Permalink
Remove all associated schedules when deleting the project (#1589)
Browse files Browse the repository at this point in the history
Deletion of a project will automatically remove all of its associated schedules and go through even though associated trigger instances or flows are running. Current behavior of Azkaban is to disallow any project deletion while the project contains any flow currently being scheduled or running. User needs to remove associated schedules first and wait for all associated flows to finish or cancel any running flows in order to delete the project. However if schedule info is part of the project zip as part of flow 2.0 design, it’s impossible for user to unschedule without removing the project which becomes a deadlock scenario. This also reduces user manual labor when deleting projects.

Tested locally, but unit test or integration test will follow up.
  • Loading branch information
burgerkingeater committed Jan 3, 2018
1 parent 1d90fb3 commit 1bb277d
Show file tree
Hide file tree
Showing 2 changed files with 19 additions and 39 deletions.
Expand Up @@ -586,6 +586,19 @@ private void handlePurgeProject(final HttpServletRequest req,
this.writeJSON(resp, ret);
}

private void removeAssociatedSchedules(final Project project) throws ServletException {
try {
for (final Schedule schedule : this.scheduleManager.getSchedules()) {
if (schedule.getProjectId() == project.getId()) {
logger.info("removing schedule " + schedule.getScheduleId());
this.scheduleManager.removeSchedule(schedule);
}
}
} catch (final ScheduleManagerException e) {
throw new ServletException(e);
}
}

private void handleRemoveProject(final HttpServletRequest req,
final HttpServletResponse resp, final Session session) throws ServletException,
IOException {
Expand All @@ -607,42 +620,7 @@ private void handleRemoveProject(final HttpServletRequest req,
return;
}

// Check if scheduled
Schedule sflow = null;
try {
for (final Schedule flow : this.scheduleManager.getSchedules()) {

if (flow.getProjectId() == project.getId()) {
sflow = flow;
break;
}
}
} catch (final ScheduleManagerException e) {
throw new ServletException(e);
}

if (sflow != null) {
this.setErrorMessageInCookie(resp, "Cannot delete. Please unschedule "
+ sflow.getScheduleName() + ".");

resp.sendRedirect(req.getRequestURI() + "?project=" + projectName);
return;
}

// Check if executing
ExecutableFlow exflow = null;
for (final ExecutableFlow flow : this.executorManager.getRunningFlows()) {
if (flow.getProjectId() == project.getId()) {
exflow = flow;
break;
}
}
if (exflow != null) {
this.setErrorMessageInCookie(resp, "Cannot delete. Executable flow "
+ exflow.getExecutionId() + " is still running.");
resp.sendRedirect(req.getRequestURI() + "?project=" + projectName);
return;
}
removeAssociatedSchedules(project);

try {
this.projectManager.removeProject(project, user);
Expand All @@ -653,7 +631,7 @@ private void handleRemoveProject(final HttpServletRequest req,
}

this.setSuccessMessageInCookie(resp, "Project '" + projectName
+ "' was successfully deleted.");
+ "' was successfully deleted and associated schedules are removed.");
resp.sendRedirect(req.getContextPath());
}

Expand Down Expand Up @@ -787,7 +765,7 @@ private void fillFlowInfo(final Project project, final String flowId,
final Flow flow = project.getFlow(flowId);
if (flow == null) {
ret.put("error",
"Flow " + flowId + " not found in project " + project.getName());
"Flow " + flowId + " not found in project " + project.getName());
return;
}

Expand Down
Expand Up @@ -77,7 +77,9 @@
<h4 class="modal-title">Delete Project</h4>
</div>
<div class="modal-body">
<p><strong>Warning:</strong> This project will be deleted and may not be recoverable.</p>
<p><strong>Warning:</strong> This project will be deleted and may not be recoverable.
All associated schedules will be removed but executing flows will remain running fine.
</p>
</div>
<div class="modal-footer">
<form id="delete-form">
Expand Down

0 comments on commit 1bb277d

Please sign in to comment.