use of cz.metacentrum.perun.taskslib.model.ExecService in project perun by CESNET.
the class EventExecServiceResolverImpl method parseEvent.
@Override
public Map<Facility, Set<ExecService>> parseEvent(String event) throws InvalidEventMessageException, ServiceNotExistsException, InternalErrorException, PrivilegeException {
log.info("I am going to process event:" + event);
/**
* Expected string format as on:
* https://projekty.ics.muni.cz/perunv3/trac
* /wiki/PerunEngineDispatcherController event|x|[timestamp][Event
* header][Event data]
*/
String eventParsingPattern = "^\\[([a-zA-Z0-9+: ]+)\\]\\[([^\\]]+)\\]\\[(.*)\\]$";
Pattern pattern = Pattern.compile(eventParsingPattern);
Matcher matcher = pattern.matcher(event);
boolean matchFound = matcher.find();
if (matchFound) {
log.debug("Message format matched ok...");
// NOT USED ANYMORE: not applicable in dispatcher
// String thisEngineID = matcher.group(1);
// // This should indeed match the current Engine instance ID, so
// let's compare it...
// if (Integer.parseInt(thisEngineID) != Integer.parseInt((String)
// propertiesBean.get("engine.unique.id"))) {
// throw new InvalidEventMessageException("Wrong Engine ID. Was:" +
// thisEngineID + ", Expected:" +
// propertiesBean.get("engine.unique.id"));
// }
// // Not being used at the moment.
// String timeStamp = matcher.group(2);
// Header should provide information regarding the target facility.
String eventHeader = matcher.group(2);
// We expect the string to contain something like this:
// facility.id=2 ???
// String headerParsingPattern = ".*facility.id\\=([0-9]+).*";
// Pattern headerPattern = Pattern.compile(headerParsingPattern);
// Matcher headerMatcher = headerPattern.matcher(eventHeader);
/*
* boolean headerMatchFound = headerMatcher.find();
* if(!headerMatchFound) { throw new InvalidEventMessageException(
* "Invalid event header. It does not contain the expected facility.id=value..."
* ); } int facilityId = Integer.parseInt(matcher.group(1));
* PerunSession perunSession =
* engineManager.getPerunSession(propertiesBean
* .getProperty("perun.principal")); Facility facility = null; try {
* facility = facilitiesManager.getFacilityById(perunSession,
* facilityId); } catch (FacilityNotExistsException e) { throw new
* InvalidEventMessageException
* ("Facility with ID "+facilityId+"does not exist.", e); } catch
* (InternalErrorException e) { throw new
* InvalidEventMessageException("Unknown error...", e); } catch
* (PrivilegeException e) { throw new
* InvalidEventMessageException("Principal "
* +propertiesBean.getProperty
* ("perun.principal")+" is not allowed to access that facility. ",
* e); }
*/
// Data should provide information regarding the target ExecService
// (Processing rule).
String eventData = matcher.group(3);
log.debug("Event data to be parsed:" + eventData);
// GET All Beans (only PerunBeans) from message
List<PerunBean> listOfBeans = new ArrayList<PerunBean>();
listOfBeans = AuditParser.parseLog(eventData);
// Prepare variables
AttributeDefinition attributeDefinition = null;
Attribute attribute = null;
Facility facility = null;
Resource resource = null;
Group group = null;
User user = null;
Member member = null;
Service service = null;
Host host = null;
// etc. ?
for (PerunBean pb : listOfBeans) {
if (pb instanceof AttributeDefinition && pb instanceof Attribute) {
attribute = (Attribute) pb;
} else if (pb instanceof Facility) {
facility = (Facility) pb;
} else if (pb instanceof Resource) {
resource = (Resource) pb;
} else if (pb instanceof Group) {
group = (Group) pb;
} else if (pb instanceof User) {
user = (User) pb;
} else if (pb instanceof Member) {
member = (Member) pb;
} else if (pb instanceof Service) {
service = (Service) pb;
} else if (pb instanceof Host) {
host = (Host) pb;
}
}
// If there is any attribute, so create AttributeDefinition
if (attribute != null) {
attributeDefinition = new AttributeDefinition(attribute);
log.debug("Attribute found in event. {}.", attributeDefinition);
}
List<Facility> facilitiesResolvedFromEvent = new ArrayList<Facility>();
List<Resource> resourcesResolvedFromEvent = new ArrayList<Resource>();
List<Service> servicesResolvedFromEvent = new ArrayList<Service>();
// =============== Resolve facilities from event======================
PerunSession perunSession = perun.getPerunSession(new PerunPrincipal(dispatcherPropertiesBean.getProperty("perun.principal.name"), dispatcherPropertiesBean.getProperty("perun.principal.extSourceName"), dispatcherPropertiesBean.getProperty("perun.principal.extSourceType")), new PerunClient());
// Try to find FACILITY in event
if (facility != null) {
try {
log.debug("Facility found in event. {}.", facility);
facilitiesResolvedFromEvent.add(facility);
resourcesResolvedFromEvent.addAll(perun.getFacilitiesManager().getAssignedResources(perunSession, facility));
} catch (FacilityNotExistsException ex) {
log.debug("Non-existing facility found while resolving event. id={}", facility.getId());
}
} else {
// Try to find RESOURCE in event
if (resource != null) {
resourcesResolvedFromEvent.add(resource);
} else {
// Try to find GROUP in event
if (group != null) {
try {
resourcesResolvedFromEvent = perun.getResourcesManager().getAssignedResources(perunSession, group);
} catch (GroupNotExistsException ex) {
log.debug("Non-existing group found while resolving event. id={}", group.getId());
}
} else {
// try to find USER in event
if (user != null) {
try {
resourcesResolvedFromEvent = perun.getUsersManager().getAllowedResources(perunSession, user);
} catch (UserNotExistsException ex) {
log.debug("Non-existing user found while resolving event. id={}", user.getId());
}
} else {
// try to find MEMBER in event
if (member != null) {
try {
resourcesResolvedFromEvent = perun.getResourcesManager().getAllowedResources(perunSession, member);
} catch (MemberNotExistsException ex) {
log.debug("Non-existing member found while resolving event. id={}", member.getId());
}
} else {
// try to find HOST in event
if (host != null) {
try {
log.debug("Host found in event.id= {}.", host.getId());
facility = perun.getFacilitiesManager().getFacilityForHost(perunSession, host);
facilitiesResolvedFromEvent.add(facility);
resourcesResolvedFromEvent.addAll(perun.getFacilitiesManager().getAssignedResources(perunSession, facility));
} catch (FacilityNotExistsException ex) {
log.debug("Host on non-existing facility found while resolving event. Host id={}", host.getId());
} catch (HostNotExistsException ex) {
log.debug("Non-existing host found while resolving event. id={}", host.getId());
}
} else {
log.warn("No match found for this event. Event={}", event);
}
}
}
}
}
}
// TODO resolve more than one service
if (service != null) {
servicesResolvedFromEvent.add(service);
}
//List<Pair<List<ExecService>, Facility>> pairs = new ArrayList<Pair<List<ExecService>, Facility>>();
Map<Facility, Set<ExecService>> result = new HashMap<Facility, Set<ExecService>>();
for (Resource r : resourcesResolvedFromEvent) {
Facility facilityResolvedFromEvent;
List<Service> servicesResolvedFromResource;
try {
facilityResolvedFromEvent = perun.getResourcesManager().getFacility(perunSession, r);
servicesResolvedFromResource = perun.getResourcesManager().getAssignedServices(perunSession, r);
// process only services resolved from event if any
if (!servicesResolvedFromEvent.isEmpty())
servicesResolvedFromResource.retainAll(servicesResolvedFromEvent);
} catch (ResourceNotExistsException ex) {
log.debug("Non-existing resource found while resolving event. Resource={}", r);
// skip to next resource
continue;
}
for (Service s : servicesResolvedFromResource) {
// TODO: Optimize with an SQL query...
List<ExecService> execServicesGenAndSend = generalServiceManager.listExecServices(perunSession, s.getId());
List<ExecService> execServices = new ArrayList<ExecService>();
for (ExecService execService : execServicesGenAndSend) {
if (execService.getExecServiceType().equals(ExecServiceType.SEND)) {
execServices.add(execService);
}
}
if (attributeDefinition != null) {
// remove from future processing services
// which don't require the found attribute
// TODO (CHECKME) This method can raise
// ServiceNotExistsException. Is it ok? Or it must be
// catch?
List<AttributeDefinition> serviceRequiredAttributes = perun.getAttributesManager().getRequiredAttributesDefinition(perunSession, s);
if (!serviceRequiredAttributes.contains(attributeDefinition))
continue;
}
if (!result.containsKey(facilityResolvedFromEvent)) {
result.put(facilityResolvedFromEvent, new HashSet<ExecService>(execServices));
} else {
result.get(facilityResolvedFromEvent).addAll(execServices);
}
}
}
log.info("I am going to return " + result.size() + " facilities.");
return result;
} else {
throw new InvalidEventMessageException("Message[" + event + "]");
}
}
use of cz.metacentrum.perun.taskslib.model.ExecService in project perun by CESNET.
the class PropagationMaintainerImpl method onTaskComplete.
@Override
public void onTaskComplete(int taskId, int clientID, String status_s, String endTimestamp, String string) {
Task completedTask = schedulingPool.getTaskById(taskId);
if (completedTask == null) {
// eh? how would that be possible?
log.error("TASK id {} reported as complete, but we do not know it... (yet?)", taskId);
return;
}
TaskStatus status = TaskStatus.NONE;
if (status_s.equals("ERROR")) {
status = TaskStatus.ERROR;
} else if (status_s.equals("DONE")) {
status = TaskStatus.DONE;
} else {
log.error("Engine reported unexpected status {} for task id {}, setting to ERROR", status_s, taskId);
status = TaskStatus.ERROR;
}
try {
Date endTime = new Date(Long.parseLong(endTimestamp));
completedTask.setEndTime(endTime);
} catch (NumberFormatException e) {
log.error("Engine reported unparsable end time {} for task id {}, setting to current time", endTimestamp, taskId);
completedTask.setEndTime(new Date(System.currentTimeMillis()));
}
// date data
if (completedTask.getExecService().getExecServiceType().equals(ExecServiceType.SEND)) {
try {
schedulingPool.setQueueForTask(completedTask, null);
} catch (InternalErrorException e) {
log.error("Could not set destination queue for task {}: {}", completedTask.getId(), e.getMessage());
}
this.setAllGenerateDependenciesToNone(completedTask);
}
if (status.equals(TaskStatus.DONE)) {
// task completed successfully
// set destination list to null to refetch them later
completedTask.setDestinations(null);
schedulingPool.setTaskStatus(completedTask, TaskStatus.DONE);
completedTask.setRecurrence(0);
log.debug("TASK {} reported as DONE", completedTask.toString());
// for GEN tasks, signal SENDs that source data are updated
if (completedTask.getExecService().getExecServiceType().equals(ExecServiceType.GENERATE)) {
List<ExecService> dependantServices = dependenciesResolver.listDependantServices(completedTask.getExecService());
for (ExecService dependantService : dependantServices) {
Task dependantTask = schedulingPool.getTask(dependantService, completedTask.getFacility());
if (dependantTask != null && dependantService.getExecServiceType().equals(ExecServiceType.SEND)) {
dependantTask.setSourceUpdated(false);
}
if (completedTask.isPropagationForced() && dependantTask.isPropagationForced()) {
log.debug("Going to force schedule dependant task " + dependantTask.getId());
taskScheduler.scheduleTask(dependantTask);
}
}
}
completedTask.setPropagationForced(false);
} else {
if (string.isEmpty()) {
// weird - task is in error and no destinations reported as
// failed...
log.warn("TASK {} ended in ERROR state with no remaining destinations.", completedTask.toString());
} else {
// task failed, some destinations remain
// resolve list of destinations
List<PerunBean> listOfBeans;
List<Destination> destinationList = new ArrayList<Destination>();
try {
listOfBeans = AuditParser.parseLog(string);
log.debug("Found list of destination beans: " + listOfBeans);
for (PerunBean bean : listOfBeans) {
destinationList.add((Destination) bean);
}
} catch (InternalErrorException e) {
log.error("Could not resolve destination from destination list");
}
if (completedTask.getDestinations() != null && !completedTask.getDestinations().isEmpty()) {
completedTask.setDestinations(destinationList);
}
}
schedulingPool.setTaskStatus(completedTask, TaskStatus.ERROR);
completedTask.setPropagationForced(false);
log.debug("Task set to ERROR state with remaining destinations: " + completedTask.getDestinations());
}
}
use of cz.metacentrum.perun.taskslib.model.ExecService in project perun by CESNET.
the class EventParserImpl method parseEvent.
@Override
public Task parseEvent(String event) throws InvalidEventMessageException, ServiceNotExistsException, InternalErrorException, PrivilegeException {
log.info("I am going to process event:" + event);
/**
* Expected string format as on:
* https://projekty.ics.muni.cz/perunv3/trac
* /wiki/PerunEngineDispatcherController event|x|[timestamp][Event
* header][Event data] New format:
* "task|[engine_id]|[task_id][is_forced]|[exec_service]|[facility]|[destination_list]|[dependency_list]"
*
*/
// String eventParsingPattern =
// "^event\\|([0-9]{1,6})\\|\\[([a-zA-Z0-9: ]+)\\]\\[([^\\]]+)\\]\\[(.*)\\]$";
String eventParsingPattern = "^task\\|([0-9]{1,6})\\|\\[([0-9]+)\\]\\[([^\\]]+)\\]\\|\\[([^\\|]+)\\]\\|\\[([^\\|]+)\\]\\|\\[([^\\|]+)\\]\\|\\[(.*)\\]$";
Pattern pattern = Pattern.compile(eventParsingPattern);
Matcher matcher = pattern.matcher(event);
boolean matchFound = matcher.find();
if (matchFound) {
log.debug("Message format matched ok...");
String thisEngineID = matcher.group(1);
// compare it...
try {
if (Integer.parseInt(thisEngineID) != Integer.parseInt((String) propertiesBean.get("engine.unique.id"))) {
throw new InvalidEventMessageException("Wrong Engine ID. Was:" + thisEngineID + ", Expected:" + propertiesBean.get("engine.unique.id"));
}
} catch (Exception e) {
throw new InvalidEventMessageException("Wrong Engine ID: parse exception", e);
}
// Data should provide information regarding the target ExecService
// (Processing rule).
String eventTaskId = matcher.group(2);
String eventIsForced = matcher.group(3);
String eventExecService = matcher.group(4);
String eventFacility = matcher.group(5);
String eventDestinationList = matcher.group(6);
String eventDependencyList = matcher.group(7);
// check possible enconding
if (!eventExecService.startsWith("ExecService")) {
eventExecService = new String(Base64.decodeBase64(eventExecService));
}
if (!eventExecService.startsWith("ExecService")) {
throw new InvalidEventMessageException("Wrong exec service: parse exception");
}
if (!eventFacility.startsWith("Facility")) {
eventFacility = new String(Base64.decodeBase64(eventFacility));
}
if (!eventFacility.startsWith("Facility")) {
throw new InvalidEventMessageException("Wrong facility: parse exception");
}
if (!eventDestinationList.startsWith("Destinations")) {
eventDestinationList = new String(Base64.decodeBase64(eventDestinationList));
}
if (!eventDestinationList.startsWith("Destinations")) {
throw new InvalidEventMessageException("Wrong destination list: parse exception");
}
log.debug("Event data to be parsed: task id " + eventTaskId + ", forced " + eventIsForced + ", facility " + eventFacility + ", exec service " + eventExecService + ", destination list " + eventDestinationList + ", dependency list " + eventDependencyList);
// Prepare variables
Facility facility;
ExecService execService;
List<Destination> destinationList = new ArrayList<Destination>();
// resolve facility
// deserialize event data
List<PerunBean> listOfBeans = AuditParser.parseLog(eventFacility);
try {
facility = (Facility) listOfBeans.get(0);
} catch (Exception e) {
throw new InvalidEventMessageException("Could not resolve facility from event [" + eventFacility + "]", e);
}
// resolve exec service
// deserialize event data
listOfBeans = AuditParser.parseLog(eventExecService);
try {
execService = (ExecService) listOfBeans.get(0);
} catch (Exception e) {
throw new InvalidEventMessageException("Could not resolve exec service from event [" + eventExecService + "]", e);
}
// resolve list of destinations
listOfBeans = AuditParser.parseLog(eventDestinationList);
log.debug("Found list of destination beans: " + listOfBeans);
// return new Pair<ExecService, Facility>(execService, facility);
try {
for (PerunBean bean : listOfBeans) {
destinationList.add((Destination) bean);
}
} catch (Exception e) {
throw new InvalidEventMessageException("Could not resolve list of destinations from event.", e);
}
Task task = new Task();
task.setId(Integer.parseInt(eventTaskId));
task.setFacility(facility);
task.setExecService(execService);
task.setDestinations(destinationList);
task.setDelay(execService.getDefaultDelay());
task.setRecurrence(execService.getDefaultRecurrence());
task.setPropagationForced(Boolean.parseBoolean(eventIsForced));
// resolve list of dependencies
if (eventDependencyList != null) {
for (String token : eventDependencyList.split("[\t ]*,[\t ]*")) {
if (token.length() > 0) {
try {
dependenciesResolver.addDependency(task, Integer.parseInt(token));
} catch (Exception e) {
throw new InvalidEventMessageException("Invalid dependency in event: " + token);
}
}
}
}
return task;
} else {
throw new InvalidEventMessageException("Invalid message format: Message[" + event + "]");
}
}
use of cz.metacentrum.perun.taskslib.model.ExecService in project perun by CESNET.
the class PropagationMaintainerImpl method rescheduleErrorTasks.
@Deprecated
private void rescheduleErrorTasks() {
for (Task task : schedulingPool.getErrorTasks()) {
log.debug("TASK " + task.toString() + " finished in error");
if (task.getEndTime() == null) {
log.error("RECOVERY FROM INCONSISTENT STATE: ERROR task does not have end_time! Setting end_time to task.getDelay + 1.");
// getDelay is in minutes, therefore we multiply it with 60*1000
Date endTime = new Date(System.currentTimeMillis() - ((task.getDelay() + 1) * 60000));
task.setEndTime(endTime);
}
int howManyMinutesAgo = (int) (System.currentTimeMillis() - task.getEndTime().getTime()) / 1000 / 60;
log.info("TASK [" + task + "] in ERROR state completed " + howManyMinutesAgo + " minutes ago.");
// check and set recurrence
int recurrence = task.getRecurrence() - 1;
if (recurrence < 0) {
// no more retries, sorry
log.info("TASK [ " + task + "] in ERROR state has no more retries, bailing out.");
schedulingPool.removeTask(task);
log.debug("TASK {} removed from database.", task.getId());
continue;
}
// If DELAY time has passed, we reschedule...
if (howManyMinutesAgo >= task.getDelay()) {
try {
task.setRecurrence(recurrence);
ExecService execService = task.getExecService();
Facility facility = task.getFacility();
log.info("TASK [ " + task + "] in ERROR state is going to be rescheduled: taskScheduler.propagateService(execService:ID " + execService.getId() + ", new Date(System.currentTimeMillis()), facility:ID " + facility.getId() + ");");
taskScheduler.propagateService(task, new Date(System.currentTimeMillis()));
log.info("TASK [" + task + "] in ERROR state has been rescheduled.");
// Also (to be sure) reschedule all Tasks that depend on
// this Task
//
// While engine starts in state GEN = ERROR, SEND = DONE
// => GEN will be rescheduled but without this SEND will
// never be propagated
List<Task> dependentTasks = dependenciesResolver.getDependants(task);
if (dependentTasks != null) {
for (Task dependantTask : dependentTasks) {
taskScheduler.propagateService(dependantTask, new Date(System.currentTimeMillis()));
log.info("{} was rescheduled because it depends on {}", dependantTask, task);
}
}
} catch (InternalErrorException e) {
log.error("{}", e);
}
}
}
/*
* Original implementation:
*
* //TODO: Take into account Recurrence! for (Task task :
* taskManager.listAllTasksInState(TaskStatus.ERROR,
* Integer.parseInt(propertiesBean.getProperty("engine.unique.id")))) {
* if (task.getEndTime() == null) { log.error(
* "RECOVERY FROM INCONSISTATE STATE: ERROR task does not have end_time! Setting end_time to task.getDelay + 1."
* ); // getDelay is in minutes, therefore we multiply it with 60*1000
* Date endTime = new Date(System.currentTimeMillis() -
* ((task.getDelay() + 1) * 60000)); task.setEndTime(endTime);
* taskManager.updateTask(task,
* Integer.parseInt(propertiesBean.getProperty("engine.unique.id"))); }
* int howManyMinutesAgo = (int) (System.currentTimeMillis() -
* task.getEndTime().getTime()) / 1000 / 60; log.info("TASK [" + task +
* "] in ERROR state completed " + howManyMinutesAgo + " minutes ago.");
* //If DELAY time has passed, we reschedule... if (howManyMinutesAgo >=
* task.getDelay()) { //check if service is still assigned on facility
* try { List<Service> assignedServices =
* Rpc.ServicesManager.getAssignedServices(engineManager.getRpcCaller(),
* task.getFacility());
* if(assignedServices.contains(task.getExecService().getService())) {
* try { taskManager.updateTask(task,
* Integer.parseInt(propertiesBean.getProperty("engine.unique.id")));
* ExecService execService = task.getExecService(); Facility facility =
* task.getFacility(); log.info("TASK [" + task +
* "] in ERROR state is going to be rescheduled: taskScheduler.propagateService(execService:ID "
* + execService.getId() +
* ", new Date(System.currentTimeMillis()), facility:ID " +
* facility.getId() + ");"); taskScheduler.propagateService(execService,
* new Date(System.currentTimeMillis()), facility); log.info("TASK [" +
* task + "] in ERROR state has been rescheduled.");
*
* //Also (to be sure) reschedule all execServices which depends on this
* exec service // //While engine starts in state GEN = ERROR, SEND =
* DONE => GEN will be rescheduled but without this SEND will never be
* propagated List<ExecService> dependentExecServices =
* Rpc.GeneralServiceManager
* .listExecServicesDependingOn(engineManager.getRpcCaller(),
* execService); if(dependentExecServices != null) { for(ExecService
* dependantExecService : dependentExecServices) {
* taskScheduler.propagateService(dependantExecService, new
* Date(System.currentTimeMillis()), facility);
* log.info("{} was rescheduled because it depends on {}",
* dependantExecService, execService); } }
*
* } catch (InternalErrorException e) { log.error(e.toString(), e); } }
* else { //delete this tasks (SEND and GEN) because service is no
* longer assigned to facility List<ExecService> execServicesGenAndSend
* =
* Rpc.GeneralServiceManager.listExecServices(engineManager.getRpcCaller
* (), task.getExecService().getService().getId()); for(ExecService
* execService : execServicesGenAndSend) { Task taskToDelete =
* taskManager.getTask(execService, task.getFacility(),
* Integer.parseInt(propertiesBean.getProperty("engine.unique.id")));
* if(taskToDelete!= null) {
* resultManager.clearByTask(taskToDelete.getId(),
* Integer.parseInt(propertiesBean.getProperty("engine.unique.id")));
* taskManager.removeTask(taskToDelete.getId(),
* Integer.parseInt(propertiesBean.getProperty("engine.unique.id"))); }
* } } } catch(PrivilegeException ex) {
* log.error("Consistency error. {}", ex); }
* catch(FacilityNotExistsException ex) {
* log.error("Consistency error - found task for non-existing facility. {}"
* , ex); } catch(ServiceNotExistsException ex) {
* log.error("Consistency error - found task for non-existing service. {}"
* , ex); } catch(InternalErrorException ex) { log.error("{}", ex); } }
* }
*/
}
use of cz.metacentrum.perun.taskslib.model.ExecService in project perun by CESNET.
the class TaskSchedulerImpl method refetchTaskInformation.
private void refetchTaskInformation(Task task) throws FacilityNotExistsException, InternalErrorException, PrivilegeException, ServiceNotExistsException {
// reread facility
log.debug("Rereading facility and exec service for task {}", task.getId());
Facility dbFacility = perun.getFacilitiesManagerBl().getFacilityById(perunSession, task.getFacilityId());
if (dbFacility == null) {
throw new FacilityNotExistsException("No facility with id " + task.getFacilityId());
}
Boolean taskModified = false;
if (!dbFacility.equals(task.getFacility())) {
task.setFacility(dbFacility);
taskModified = true;
}
// reread exec service (and service)
ExecService dbExecService = generalServiceManager.getExecService(perunSession, task.getExecServiceId());
if (dbExecService == null) {
throw new ServiceNotExistsException("No exec service with id " + task.getExecServiceId());
}
if (!dbExecService.equals(task.getExecService())) {
task.setExecService(dbExecService);
taskModified = true;
}
if (taskModified) {
log.debug("Task components have changed, updating task {}", task.getId());
schedulingPool.setTaskStatus(task, task.getStatus());
}
}
Aggregations