public void removeJobServer(GearmanJobServerConnection conn) throws IllegalArgumentException, IllegalStateException { if (!runState.equals(state.RUNNING)) { throw new IllegalStateException( "JobServers can not be removed " + "once shutdown has been commenced."); } // TODO, make this better Iterator<GearmanJobServerSession> iter = sessionsMap.values().iterator(); GearmanJobServerSession session = null; boolean foundit = false; while (iter.hasNext() && !foundit) { session = iter.next(); if (session.getConnection().equals(conn)) { foundit = true; } } if (!foundit) { throw new IllegalArgumentException( "JobServer " + conn + " has not" + " been registered with this client."); } shutDownSession(session); LOG.info("Removed job server " + conn + " from client " + this); }
public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { TimeUnit sessionUnit = TimeUnit.MILLISECONDS; long timeLeft = -1; long timeOutInMills = timeout < 0 ? -1 : TimeUnit.MILLISECONDS.convert(timeout, unit) + System.currentTimeMillis(); if (getNumberofActiveJobs() == 0) { return true; } for (GearmanJobServerSession curSession : sessionsMap.values()) { if (!(curSession.isInitialized())) { continue; } // negative timeout means block till completion if (timeout >= 0) { timeLeft = timeOutInMills - System.currentTimeMillis(); if (timeLeft <= 0) { LOG.warn("awaitTermination exceeded timeout."); break; } } try { curSession.waitForTasksToComplete(timeLeft, sessionUnit); } catch (TimeoutException te) { LOG.info("timed out waiting for all tasks to complete"); break; } } return getNumberofActiveJobs() == 0; }
private void addNewJob(GearmanSessionEvent event) { byte[] handle, data, functionNameBytes, unique; GearmanPacket p = event.getPacket(); GearmanJobServerSession sess = event.getSession(); String functionName; handle = p.getDataComponentValue(GearmanPacket.DataComponentName.JOB_HANDLE); functionNameBytes = p.getDataComponentValue(GearmanPacket.DataComponentName.FUNCTION_NAME); data = p.getDataComponentValue(GearmanPacket.DataComponentName.DATA); unique = p.getDataComponentValue(DataComponentName.UNIQUE_ID); functionName = ByteUtils.fromUTF8Bytes(functionNameBytes); FunctionDefinition def = functionMap.get(functionName); if (def == null) { GearmanTask gsr = new GearmanTask( new GearmanPacketImpl(GearmanPacketMagic.REQ, GearmanPacketType.WORK_FAIL, handle)); sess.submitTask(gsr); } else { GearmanFunction function = def.getFactory().getFunction(); function.setData(data); function.setJobHandle(handle); function.registerEventListener(sess); if (unique != null && unique.length > 0) { function.setUniqueId(unique); } functionList.add(function); } }
private void driveClientIO() throws IOException, GearmanException { for (GearmanJobServerSession sess : sessionsMap.values()) { int interestOps = SelectionKey.OP_READ; if (sess.sessionHasDataToWrite()) { interestOps |= SelectionKey.OP_WRITE; } try { sess.getSelectionKey().interestOps(interestOps); } catch (IllegalStateException ise) { LOG.warn("Unable to drive IO for session " + sess + "," + " skipping.", ise); continue; } } ioAvailable.selectNow(); Set<SelectionKey> keys = ioAvailable.selectedKeys(); LOG.trace( "Driving IO for client " + this + ". " + keys.size() + " session(s) currently available for IO"); Iterator<SelectionKey> iter = keys.iterator(); while (iter.hasNext()) { SelectionKey key = iter.next(); GearmanJobServerSession s = sessionsMap.get(key); s.driveSessionIO(); } }
public List<Runnable> shutdownNow() { runState = state.SHUTTINGDOWN; LOG.info("Commencing immediate shutdown of client: " + this); timer.cancel(); Iterator<GearmanJobServerSession> sessions = sessionsMap.values().iterator(); while (sessions.hasNext()) { GearmanJobServerSession curSession = sessions.next(); if (!curSession.isInitialized()) { continue; } try { curSession.closeSession(); } catch (Exception e) { LOG.warn( "Failed to closes session " + curSession + " while performing immediate shutdown of client " + this + ". Encountered the following exception " + e); } sessions.remove(); } sessionsMap.clear(); sessionsMap = null; runState = state.TERMINATED; try { ioAvailable.close(); } catch (IOException ioe) { LOG.warn("Encountered IOException while closing selector for client ", ioe); } LOG.info("Completed shutdown of client: " + this); return new ArrayList<Runnable>(); }
/* * For the time being this will always return an empty list of * exceptions because closeSession does not throw an exception */ private List<Exception> shutDownWorker(boolean completeTasks) { LOG.info("Commencing shutdowm of worker " + this); ArrayList<Exception> exceptions = new ArrayList<Exception>(); // This gives any jobs in flight a chance to complete if (executorService != null) { if (completeTasks) { executorService.shutdown(); } else { executorService.shutdownNow(); } } for (GearmanJobServerSession sess : sessionMap.values()) { sess.closeSession(); } try { ioAvailable.close(); } catch (IOException ioe) { LOG.warn("Encountered IOException while closing selector for worker: ", ioe); } state = State.IDLE; LOG.info("Completed shutdowm of worker " + this); return exceptions; }
public boolean hasConnection(GearmanJobServerConnection conn) { for (GearmanJobServerSession sess : sessionsMap.values()) { if (sess.getConnection().equals(conn)) { return true; } } return false; }
public boolean hasServer(GearmanJobServerConnection conn) { boolean foundIt = false; for (GearmanJobServerSession sess : sessionMap.values()) { if (sess.getConnection().equals(conn)) { foundIt = true; } } return foundIt; }
private void shutDownSession(GearmanJobServerSession s) { if (s.isInitialized()) { SelectionKey k = s.getSelectionKey(); if (k != null) { sessionsMap.remove(k); k.cancel(); } s.closeSession(); } sessionJobsMap.remove(s); }
public List<GearmanJobServerConnection> getSetOfJobServers() throws IllegalStateException { if (!runState.equals(state.RUNNING)) { throw new IllegalStateException(CLIENT_NOT_ACTIVE); } ArrayList<GearmanJobServerConnection> retSet = new ArrayList<GearmanJobServerConnection>(); for (GearmanJobServerSession sess : sessionsMap.values()) { retSet.add(sess.getConnection()); } return retSet; }
public void handleSessionEvent(GearmanSessionEvent event) throws IllegalArgumentException, IllegalStateException { GearmanPacket p = event.getPacket(); GearmanJobServerSession s = event.getSession(); GearmanPacketType t = p.getPacketType(); LOG.debug( "Worker " + this + " handling session event" + " ( Session = " + s + " Event = " + t + " )"); switch (t) { case JOB_ASSIGN: // TODO Figure out what the right behavior is if JobUUIDRequired was false when we submitted // but is now true taskMap.remove(s); addNewJob(event); break; case JOB_ASSIGN_UNIQ: // TODO Figure out what the right behavior is if JobUUIDRequired was true when we submitted // but is now false taskMap.remove(s); addNewJob(event); break; case NOOP: taskMap.remove(s); break; case NO_JOB: GearmanTask preSleepTask = new GearmanTask( new GrabJobEventHandler(s), new GearmanPacketImpl( GearmanPacketMagic.REQ, GearmanPacketType.PRE_SLEEP, new byte[0])); taskMap.put(s, preSleepTask); s.submitTask(preSleepTask); break; case ECHO_RES: break; case OPTION_RES: break; case ERROR: s.closeSession(); break; default: LOG.warn( "Received unknown packet type " + t + " from session " + s + ". Closing connection."); s.closeSession(); } }
public boolean addServer(GearmanJobServerConnection conn) throws IllegalArgumentException, IllegalStateException { if (conn == null) { throw new IllegalArgumentException("Connection can not be null"); } // this is a sub-optimal way to look for dups, but addJobServer // ops should be infrequent enough that this should be a big penalty for (GearmanJobServerSession sess : sessionMap.values()) { if (sess.getConnection().equals(conn)) { return true; } } GearmanJobServerSession session = new GearmanJobServerSession(conn); if (ioAvailable == null) { try { ioAvailable = Selector.open(); } catch (IOException ioe) { LOG.warn("Failed to connect to job server " + conn + ".", ioe); return false; } } try { session.initSession(ioAvailable, this); } catch (IOException ioe) { LOG.warn("Failed to initialize session with job server " + conn + ".", ioe); return false; } SelectionKey key = session.getSelectionKey(); if (key == null) { String msg = "Session " + session + " has a null " + "selection key. Server will not be added to worker."; LOG.warn(msg); throw new IllegalStateException(msg); } sessionMap.put(key, session); GearmanPacket p = new GearmanPacketImpl( GearmanPacketMagic.REQ, GearmanPacketType.SET_CLIENT_ID, ByteUtils.toUTF8Bytes(id)); session.submitTask(new GearmanTask(p)); for (FunctionDefinition def : functionMap.values()) { p = generateCanDoPacket(def); session.submitTask(new GearmanTask(p)); // NOPMD } p = new GearmanPacketImpl(GearmanPacketMagic.REQ, getGrabJobPacketType(), new byte[0]); GearmanTask gsr = new GearmanTask(new GrabJobEventHandler(session), p); taskMap.put(session, gsr); session.submitTask(gsr); LOG.debug("Added server " + conn + " to worker " + this); return true; }
public boolean addJobServer(GearmanJobServerConnection newconn, boolean serverForwardsExceptions) throws IllegalArgumentException, IllegalStateException { // TODO remove this restriction if (!(newconn instanceof GearmanNIOJobServerConnection)) { throw new IllegalArgumentException( "Client currently only " + "supports " + GearmanNIOJobServerConnection.class.getName() + " connections."); } GearmanNIOJobServerConnection conn = (GearmanNIOJobServerConnection) newconn; if (!runState.equals(state.RUNNING)) { throw new RejectedExecutionException("Client has been shutdown"); } GearmanJobServerSession session = new GearmanJobServerSession(conn); if (sessionsMap.values().contains(session)) { LOG.debug( "The server " + newconn + " was previously " + "added to the client. Ignoring add request."); return true; } try { if (ioAvailable == null) { ioAvailable = Selector.open(); } session.initSession(ioAvailable, this); SelectionKey key = session.getSelectionKey(); sessionsMap.put(key, session); } catch (IOException ioe) { LOG.warn("Failed to connect to job server " + newconn + ".", ioe); return false; } if (serverForwardsExceptions && !setForwardExceptions(session)) { return false; } sessionJobsMap.put(session, new HashMap<JobHandle, GearmanJobImpl>()); LOG.info("Added connection " + conn + " to client " + this); return true; }
private boolean setForwardExceptions(GearmanJobServerSession session) { GearmanServerResponseHandler optionReqHandler = new GearmanServerResponseHandler() { boolean isDone = false; public boolean isDone() { return isDone; } public void handleEvent(GearmanPacket event) throws GearmanException { GearmanPacketType type = event.getPacketType(); if (type.equals(GearmanPacketType.OPTION_RES) && Arrays.equals(EXCEPTIONS, event.getData())) { isDone = true; } } }; GearmanTask setExceptionsTask = new GearmanTask( optionReqHandler, new GearmanPacketImpl( GearmanPacketMagic.REQ, GearmanPacketType.OPTION_REQ, EXCEPTIONS)); session.submitTask(setExceptionsTask); Exception e = null; boolean success = false; try { success = driveRequestTillState(setExceptionsTask, GearmanTask.State.FINISHED); } catch (IOException ioe) { e = ioe; } if (!success) { if (e != null) { LOG.info("Failed to set forward-exceptions option to " + session.getConnection(), e); } else { LOG.info("Failed to set forward-exceptions option to " + session.getConnection()); } return false; } return true; }
private void statistics() { if (this.statisticsCount >= 4294967296L) { this.statisticsCount = 0; } else { this.statisticsCount++; } if (this.statisticsCount % 100 == 0) { if (executorService != null) { LOG_STATISTICS.info("statistics[thread]:" + executorService.toString()); } Collection<GearmanJobServerSession> sessions = sessionMap.values(); for (GearmanJobServerSession session : sessions) { LOG_STATISTICS.info( "statistics[task]:" + session.toString() + " ActiveTasks:" + session.getNumberOfActiveTasks()); } } }
private GearmanJobServerSession getSessionForTask() throws IOException { if (sessionsMap.values().isEmpty()) { throw new IOException("No servers registered with client"); } ArrayList<GearmanJobServerSession> sessions = new ArrayList<GearmanJobServerSession>(); sessions.addAll(sessionsMap.values()); Random rand = new Random(System.currentTimeMillis()); int s = rand.nextInt(sessions.size()); GearmanJobServerSession session = sessions.get(s); IOException ioe = new IOException("No servers available for client"); for (int i = 0; i < sessions.size(); i++) { if (!session.isInitialized()) { try { session.initSession(ioAvailable, this); sessionsMap.put(session.getSelectionKey(), session); } catch (Exception e) { if (sessions.size() > 1) { // try next one int prev = s; s = (s + 1) % sessions.size(); session = sessions.get(s); LOG.warn( "Got exception attempting to retrieve " + "session for task. Try next server at " + "pos={}, previous pos={}", s, prev); continue; } else { break; } } } return session; } throw ioe; }
public byte[] echo(byte[] data) throws IOException, GearmanException { if (!runState.equals(state.RUNNING)) { throw new IllegalStateException(CLIENT_NOT_ACTIVE); } GearmanPacket echoRequest = new GearmanPacketImpl(GearmanPacketMagic.REQ, GearmanPacketType.ECHO_REQ, data); GearmanEchoResponseHandler handler = new GearmanEchoResponseHandler(); GearmanTask t = new GearmanTask(handler, echoRequest); GearmanJobServerSession session = getSessionForTask(); session.submitTask(t); LOG.info( "Client " + this + " has submitted echo request " + "(payload = " + ByteUtils.toHex(data) + " to session " + session); if (!driveRequestTillState(t, GearmanTask.State.FINISHED)) { throw new GearmanException("Failed to execute echo request " + t + " to session " + session); } LOG.info("Client " + this + " has completed echo request " + "to session " + session); return handler.getResults(); }
private GearmanJobStatus updateJobStatus(byte[] jobhandle, GearmanJobServerSession session) throws IOException, IllegalStateException, GearmanException { if (!runState.equals(state.RUNNING)) { throw new IllegalStateException(CLIENT_NOT_ACTIVE); } if (jobhandle == null || jobhandle.length == 0) { throw new IllegalStateException("Invalid job handle. Handle must" + " not be null nor empty"); } GearmanPacket statusRequest = new GearmanPacketImpl(GearmanPacketMagic.REQ, GearmanPacketType.GET_STATUS, jobhandle); GearmanServerResponseHandler handler = (GearmanServerResponseHandler) new GearmanJobStatusImpl(); GearmanTask t = new GearmanTask(handler, statusRequest); session.submitTask(t); if (!driveRequestTillState(t, GearmanTask.State.FINISHED)) { throw new GearmanException( "Failed to execute jobstatus request " + t + " to session " + session); } return (GearmanJobStatus) handler; }
private void sendToAll(GearmanServerResponseHandler handler, GearmanPacket p) { GearmanTask gsr = new GearmanTask(handler, p); for (GearmanJobServerSession sess : sessionMap.values()) { sess.submitTask(gsr); } }
public void work() { if (!state.equals(State.IDLE)) { throw new IllegalStateException( "Can not call work while worker " + "is running or shutting down"); } state = State.RUNNING; // a map keeping track of sessions with connection errors // (to avoid printing an error about them in every reconnect attempt) Map<GearmanJobServerSession, Boolean> havingConnectionError = new HashMap<GearmanJobServerSession, Boolean>(); while (isRunning()) { // look for sessions which have been disconnected and attempt to reconnect. for (Iterator<GearmanJobServerSession> iter = sessionMap.values().iterator(); iter.hasNext(); ) { GearmanJobServerSession sess = iter.next(); if (!sess.isInitialized()) { try { // reconnect, unregister old selection key and register new one SelectionKey oldKey = sess.isInitialized() ? sess.getSelectionKey() : null; sess.initSession(ioAvailable, this); if (oldKey != null) { iter.remove(); } sessionMap.put(sess.getSelectionKey(), sess); // register all functions with the newly reconnected server for (FunctionDefinition d : functionMap.values()) { GearmanTask gsr = new GearmanTask(null, generateCanDoPacket(d)); sess.submitTask(gsr); } GearmanPacket p = new GearmanPacketImpl( GearmanPacketMagic.REQ, GearmanPacketType.SET_CLIENT_ID, ByteUtils.toUTF8Bytes(id)); sess.submitTask(new GearmanTask(p)); GearmanTask sessTask = new GearmanTask( new GrabJobEventHandler(sess), new GearmanPacketImpl( GearmanPacketMagic.REQ, getGrabJobPacketType(), new byte[0])); sess.submitTask(sessTask); sess.driveSessionIO(); // log reconnection message if (havingConnectionError.get(sess)) { LOG.info("Re-established connection to " + sess.getConnection().toString()); } havingConnectionError.put(sess, false); } catch (IOException e) { if (!havingConnectionError.get(sess)) { LOG.warn("Error connecting to " + sess + ", will keep trying.."); } havingConnectionError.put(sess, true); try { Thread.sleep(50); } catch (InterruptedException e1) { } } } else { havingConnectionError.put(sess, false); } } for (GearmanJobServerSession sess : sessionMap.values()) { // if still disconnected, skip if (!sess.isInitialized()) { continue; } int interestOps = SelectionKey.OP_READ; if (sess.sessionHasDataToWrite()) { interestOps |= SelectionKey.OP_WRITE; } sess.getSelectionKey().interestOps(interestOps); } try { ioAvailable.select(1); } catch (IOException io) { LOG.warn("Receieved IOException while" + " selecting for IO", io); } for (SelectionKey key : ioAvailable.selectedKeys()) { GearmanJobServerSession sess = sessionMap.get(key); if (sess == null) { LOG.warn("Worker does not have " + "session for key " + key); continue; } if (!sess.isInitialized()) { continue; } try { GearmanTask sessTask = taskMap.get(sess); if (sessTask == null) { sessTask = new GearmanTask( // NOPMD new GrabJobEventHandler(sess), new GearmanPacketImpl( GearmanPacketMagic.REQ, getGrabJobPacketType(), new byte[0])); taskMap.put(sess, sessTask); sess.submitTask(sessTask); LOG.debug( "Worker: " + this + " submitted a " + sessTask.getRequestPacket().getPacketType() + " to session: " + sess); } sess.driveSessionIO(); // For the time being we will execute the jobs synchronously // in the future, I expect to change this. if (!functionList.isEmpty()) { GearmanFunction fun = functionList.remove(); submitFunction(fun); statistics(); } } catch (IOException ioe) { LOG.warn("Received IOException while driving" + " IO on session " + sess, ioe); sess.closeSession(); continue; } } } shutDownWorker(true); }
public <T> Future<T> submit(Callable<T> task) { if (task == null) { throw new IllegalStateException("Null task was submitted to " + "gearman client"); } if (!runState.equals(state.RUNNING)) { throw new RejectedExecutionException("Client has been shutdown"); } if (!(task instanceof GearmanServerResponseHandler)) { throw new RejectedExecutionException( "Task must implement the " + GearmanServerResponseHandler.class + " interface to" + " submitted to this client"); } GearmanJobImpl job = (GearmanJobImpl) task; GearmanServerResponseHandler handler = (GearmanServerResponseHandler) job; if (job.isDone()) { throw new RejectedExecutionException("Task can not be resubmitted "); } GearmanJobServerSession session = null; try { session = getSessionForTask(); } catch (IOException ioe) { throw new RejectedExecutionException(ioe); } job.setJobServerSession(session); GearmanPacket submitRequest = getPacketFromJob(job); GearmanTask submittedJob = new GearmanTask(handler, submitRequest); session.submitTask(submittedJob); LOG.info( "Client " + this + " has submitted job " + job + // NOPMD " to session " + session + ". Job has been added to the " + // NOPMD "active job queue"); try { jobAwatingCreation = job; if (!(driveRequestTillState(submittedJob, GearmanTask.State.RUNNING))) { throw new RejectedExecutionException( "Timed out waiting for" + " submission of " + job + " to complete"); } } catch (IOException ioe) { LOG.warn("Client " + this + " encounted an " + "IOException while drivingIO", ioe); throw new RejectedExecutionException( "Failed to successfully " + "submit" + job + " due to IOException", ioe); } finally { jobAwatingCreation = null; } return (Future<T>) job; }