/** * Submit a list of jobs to Cook scheduler. It will <br> * -- firstly associate each job with the provided {@link JobListener}<br> * -- secondly submit these jobs to Cook scheduler and track them until they complete. * * @param jobs The list of jobs expected to submit. * @param listener specifies an instance of {@link JobListener} listening all job status updates. * @throws JobClientException */ public void submit(List<Job> jobs, JobListener listener) throws JobClientException { // It is ok to change the listeners map even if the actual submission fails because it won't // update the internal status map {@code _activeUUIDTOJob}. for (Job job : jobs) { _activeUUIDToListener.put(job.getUUID(), listener); } submit(jobs); }
/** * Query jobs for a given list of job {@link UUID}s. If the list size is larger that the {@code * _batchRequestSize}, it will partition the list into smaller lists and query them respectively * and return all query results together. * * @param uuids specifies a list of job {@link UUID}s expected to query. * @return a {@link ImmutableMap} from job {@link UUID} to {@link Job}. * @throws JobClientException */ public ImmutableMap<UUID, Job> query(Collection<UUID> uuids) throws JobClientException { final List<NameValuePair> allParams = new ArrayList<NameValuePair>(uuids.size()); for (UUID uuid : uuids) { allParams.add(new BasicNameValuePair("job", uuid.toString())); } final ImmutableMap.Builder<UUID, Job> UUIDToJob = ImmutableMap.builder(); // Partition a large query into small queries. for (final List<NameValuePair> params : Lists.partition(allParams, _batchRequestSize)) { HttpResponse httpResponse; HttpRequestBase httpRequest; try { URIBuilder uriBuilder = new URIBuilder(_uri); uriBuilder.addParameters(params); httpRequest = new HttpGet(uriBuilder.build()); httpResponse = _httpClient.execute(httpRequest); } catch (IOException | URISyntaxException e) { throw releaseAndCreateException( null, "Can not submit GET request " + params + " via uri " + _uri, e); } // Check status code. final StatusLine statusLine = httpResponse.getStatusLine(); // Base on the decision graph // http://clojure-liberator.github.io/liberator/tutorial/decision-graph.html // The status code for the proper GET response is 200. if (statusLine.getStatusCode() != HttpStatus.SC_OK) { throw releaseAndCreateException( httpRequest, "The response of GET request " + params + " via uri " + _uri + ": " + statusLine.getReasonPhrase() + ", " + statusLine.getStatusCode(), null); } // Parse the response. String response = null; try { // parse the response to string. final HttpEntity entity = httpResponse.getEntity(); response = EntityUtils.toString(entity); // Ensure that the entity content has been fully consumed and the underlying stream has been // closed. EntityUtils.consume(entity); for (Job job : Job.parseFromJSON(response, _instanceDecorator)) { UUIDToJob.put(job.getUUID(), job); } } catch (JSONException | ParseException | IOException e) { throw new JobClientException( "Can not parse the response = " + response + " for GET request " + params + " via uri " + _uri, e); } finally { httpRequest.releaseConnection(); } } return UUIDToJob.build(); }
/** * Submit a list of jobs to Cook scheduler and start to track these jobs until they complete. Note * that jobs submitted through this API will not be listened by any listener. * * @param jobs specifies a list of {@link Job}s to be submitted. * @return the response string from Cook scheduler rest endpoint. * @throws JobClientException */ public void submit(List<Job> jobs) throws JobClientException { JSONObject json; try { json = Job.jsonizeJob(jobs); } catch (JSONException e) { throw new JobClientException("Can not jsonize jobs to submit.", e); } HttpResponse httpResponse; HttpRequestBase httpRequest = makeHttpPost(_uri, json); try { httpResponse = executeWithRetries(httpRequest, 5, 10); } catch (IOException e) { throw releaseAndCreateException( httpRequest, "Can not submit POST request " + json + " via uri " + _uri, e); } // Get the response string. StatusLine statusLine = httpResponse.getStatusLine(); HttpEntity entity = httpResponse.getEntity(); if (entity == null) { throw releaseAndCreateException(httpRequest, "The response entity is null!", null); } String response = null; try { response = EntityUtils.toString(entity); // Ensure that the entity content has been fully consumed and the underlying stream has been // closed. EntityUtils.consume(entity); } catch (ParseException | IOException e) { throw releaseAndCreateException( httpRequest, "Can not parse the response for POST request " + json + " via uri " + _uri, e); } if (_log.isDebugEnabled()) { _log.debug("Response String for submitting jobs" + json.toString() + " is " + response); } // Base on the decision graph // http://clojure-liberator.github.io/liberator/tutorial/decision-graph.html // If the jobs are submitted successfully, the status code is 201. // If a job uses a UUID which has been used before, the returned status code is 400 and the // return message is something like: // clojure.lang.ExceptionInfo: UUID 26719da8-194f-44f9-9e6d-8a17500f5109 already used {:uuid // #uuid "26719da8-194f-44f9-9e6d-8a17500f5109"} // A flag to indicate if the submission is successful. boolean isSuccess = false; if (null != statusLine && statusLine.getStatusCode() == HttpStatus.SC_CREATED) { isSuccess = true; _log.info("Successfully execute POST request with data " + json + " via uri " + _uri); } else if (null != statusLine && statusLine.getStatusCode() >= HttpStatus.SC_BAD_REQUEST) { final Pattern patternUUID = Pattern.compile( "[a-f0-9]{8}-[a-f0-9]{4}-4[a-f0-9]{3}-[89aAbB][a-f0-9]{3}-[a-f0-9]{12} already used"); final Matcher matchUUID = patternUUID.matcher(response); if (matchUUID.find()) { _log.info( "Successfully execute POST request with several retries " + json + " via uri " + _uri); isSuccess = true; } else { _log.warn( "Failed to execute POST request with several retries " + json + " via uri " + _uri); } } if (null != httpRequest) { httpRequest.releaseConnection(); } if (isSuccess) { // Update status map. for (Job job : jobs) { _activeUUIDToJob.put(job.getUUID(), job); } } else { _log.error("Failed to submit jobs " + json.toString()); throw new JobClientException( "The response of POST request " + json + " via uri " + _uri + ": " + statusLine.getReasonPhrase() + ", " + statusLine.getStatusCode()); } }