private void retry(Runnable f, String onRetriesExceededMessage) { retry(f, failure -> { throw new ExcessiveRedisFailureRetries(onRetriesExceededMessage, failure); }); }
private <T> T retry(Supplier<T> f, String onRetriesExceededMessage) { return retry(f, failure -> { throw new ExcessiveRedisFailureRetries(onRetriesExceededMessage, failure); }); }
@Override public List<Task> list() { return retry(() -> redisClientDelegate.withCommandsClient(client -> { return client.smembers(RUNNING_TASK_KEY).stream().map(this::get).collect(Collectors.toList()); }), "Getting all running tasks"); }
public List<Object> getResultObjects(JedisTask task) { String resultId = "taskResult:" + task.getId(); return retry(() -> clientForTask(task).withCommandsClient(client -> { return client.lrange(resultId, 0, -1); }), format("Getting results for task %s", task.getId())) .stream() .map(o -> { try { return mapper.readValue(o, Map.class); } catch (IOException e) { throw new RuntimeException("Failed to convert result object to map", e); } }) .collect(Collectors.toList()); }
public void addResultObjects(List<Object> objects, JedisTask task) { String resultId = "taskResult:" + task.getId(); String[] values = objects.stream() .map(o -> { try { return mapper.writeValueAsString(o); } catch (JsonProcessingException e) { throw new RuntimeException("Failed to convert object to string", e); } }) .collect(Collectors.toList()) .toArray(new String[objects.size()]); log.debug("Adding results to task {} (results: {})", task.getId(), values); retry(() -> redisClientDelegate.withCommandsClient(client -> { client.rpush(resultId, values); client.expire(resultId, TASK_TTL); }), format("Adding results to task %s", task.getId())); }
public List<Status> getHistory(JedisTask task) { String historyId = "taskHistory:" + task.getId(); RedisClientDelegate client = clientForTask(task); return retry(() -> client.withCommandsClient(c -> { return c.lrange(historyId, 0, -1); }), format("Getting history for task %s", task.getId())) .stream() .map(h -> { Map<String, String> history; try { history = mapper.readValue(h, HISTORY_TYPE); } catch (IOException e) { throw new RuntimeException("Could not convert history json to type", e); } return TaskDisplayStatus.create(DefaultTaskStatus.create(history.get("phase"), history.get("status"), TaskState.valueOf(history.get("state")))); }) .collect(Collectors.toList()); }
public void set(String id, JedisTask task) { String taskId = "task:" + task.getId(); Map<String, String> data = new HashMap<>(); data.put("id", task.getId()); data.put("startTimeMs", Long.toString(task.getStartTimeMs())); data.put("ownerId", task.getOwnerId()); retry(() -> redisClientDelegate.withCommandsClient(client -> { client.hmset(taskId, data); client.expire(taskId, TASK_TTL); client.sadd(RUNNING_TASK_KEY, id); }), format("Writing task %s", id)); }
public DefaultTaskStatus currentState(JedisTask task) { String historyId = "taskHistory:" + task.getId(); RedisClientDelegate client = clientForTask(task); String state = retry(() -> client.withCommandsClient(c -> { return c.lindex(historyId, -1); }), format("Getting current state for task %s", task.getId())); Map<String, String> history; try { history = mapper.readValue(state, HISTORY_TYPE); } catch (IOException e) { throw new RuntimeException("Failed converting task history json to object", e); } return DefaultTaskStatus.create(history.get("phase"), history.get("status"), TaskState.valueOf(history.get("state"))); }
@Override public Task get(String id) { Map<String, String> taskMap = retry(() -> redisClientDelegate.withCommandsClient(client -> { return client.hgetAll("task:" + id); }), format("Getting task ID %s", id)); boolean oldTask = redisClientDelegatePrevious.isPresent() && (taskMap == null || taskMap.isEmpty()); if (oldTask) { try { taskMap = redisClientDelegatePrevious.get().withCommandsClient(client -> { return client.hgetAll("task:" + id); }); } catch (Exception e) { // Failed to hit old redis, let's not blow up on that return null; } } if (taskMap.containsKey("id") && taskMap.containsKey("startTimeMs")) { return new JedisTask( taskMap.get("id"), Long.parseLong(taskMap.get("startTimeMs")), this, taskMap.get("ownerId"), oldTask ); } return null; }
@Override public Task getByClientRequestId(String clientRequestId) { final String clientRequestKey = getClientRequestKey(clientRequestId); String existingTask = retry(() -> redisClientDelegate.withCommandsClient(client -> { return client.get(clientRequestKey); }), format("Getting task by client request ID %s", clientRequestId)); if (existingTask == null) { if (redisClientDelegatePrevious.isPresent()) { try { existingTask = redisClientDelegatePrevious.get().withCommandsClient(client -> { return client.get(clientRequestKey); }); } catch (Exception e) { // Failed to hit old redis, let's not blow up on that existingTask = null; } } } if (existingTask != null) { return get(existingTask); } return null; }
public void addToHistory(DefaultTaskStatus status, JedisTask task) { String historyId = "taskHistory:" + task.getId(); Map<String, String> data = new HashMap<>(); data.put("phase", status.getPhase()); data.put("status", status.getStatus()); data.put("state", status.getState().toString()); String hist; try { hist = mapper.writeValueAsString(data); } catch (JsonProcessingException e) { throw new RuntimeException("Failed converting task history to json", e); } retry(() -> redisClientDelegate.withCommandsClient(client -> { client.rpush(historyId, hist); client.expire(historyId, TASK_TTL); if (status.isCompleted()) { client.srem(RUNNING_TASK_KEY, task.getId()); } }), format("Adding status history to task %s: %s", task.getId(), status)); }
@Override public Task create(String phase, String status, String clientRequestId) { String taskKey = getClientRequestKey(clientRequestId); String taskId = UUID.randomUUID().toString(); JedisTask task = new JedisTask(taskId, System.currentTimeMillis(), this, ClouddriverHostname.ID, false); addToHistory(DefaultTaskStatus.create(phase, status, TaskState.STARTED), task); set(taskId, task); Long newTask = retry(() -> redisClientDelegate.withCommandsClient(client -> { return client.setnx(taskKey, taskId); }), "Registering task with index"); if (newTask != 0) { return task; } // There's an existing taskId for this key, clean up what we just created and get the existing task addToHistory(DefaultTaskStatus.create(phase, "Duplicate of " + clientRequestId, TaskState.FAILED), task); return getByClientRequestId(clientRequestId); }