mirror of https://github.com/reiseburo/whoas
Rebuild the Publisher class in Java
This commit is contained in:
parent
8a11a25ed2
commit
67af6a1a25
|
@ -5,21 +5,20 @@ import org.joda.time.DateTime
|
|||
|
||||
|
||||
class HookRequest {
|
||||
@JsonProperty
|
||||
public Long retries
|
||||
|
||||
@JsonProperty
|
||||
private Long retries
|
||||
public String url
|
||||
|
||||
@JsonProperty
|
||||
private String url
|
||||
public String postData
|
||||
|
||||
@JsonProperty
|
||||
private String postData
|
||||
public DateTime deliverAfter
|
||||
|
||||
@JsonProperty
|
||||
private DateTime deliverAfter
|
||||
|
||||
@JsonProperty
|
||||
private String contentType
|
||||
public String contentType
|
||||
|
||||
/** Constructor for Jackson */
|
||||
HookRequest() { }
|
||||
|
|
|
@ -1,110 +0,0 @@
|
|||
package com.github.lookout.whoas
|
||||
|
||||
import javax.ws.rs.client.Client
|
||||
import javax.ws.rs.client.ClientBuilder
|
||||
import javax.ws.rs.client.Entity
|
||||
import javax.ws.rs.client.Invocation
|
||||
import javax.ws.rs.core.Response
|
||||
import javax.ws.rs.ProcessingException
|
||||
import org.slf4j.Logger
|
||||
import org.slf4j.LoggerFactory
|
||||
|
||||
|
||||
/**
|
||||
* Publisher is the class responsible for implementing the *actual* HTTP
|
||||
* request logic for Whoas
|
||||
*/
|
||||
class Publisher {
|
||||
private final String DEFAULT_CONTENT_TYPE = 'application/json'
|
||||
/** Maximum number of failures we will retry on */
|
||||
private final int DEFAULT_MAX_RETRIES = 5
|
||||
|
||||
private final int DEFAULT_BACKOFF_MILLIS = 50
|
||||
private final int DEFAULT_BACKOFF_MAX_MILLIS = (10 * 1000)
|
||||
|
||||
private Client jerseyClient
|
||||
private int maxRetries
|
||||
private Logger logger = LoggerFactory.getLogger(Publisher.class)
|
||||
|
||||
Publisher() {
|
||||
this.jerseyClient = ClientBuilder.newClient()
|
||||
this.maxRetries = DEFAULT_MAX_RETRIES
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish the request using the appropriate backoff and retry logic
|
||||
* defined in the Whoas documentation
|
||||
*/
|
||||
Boolean publish(HookRequest request) {
|
||||
Response response
|
||||
Boolean retryableExc = false
|
||||
Invocation inv = buildInvocationFrom(request)
|
||||
try {
|
||||
response = inv.invoke()
|
||||
String responseBody = response.readEntity(String.class)
|
||||
}
|
||||
catch (ProcessingException exc) {
|
||||
logger.warn("\"POST\" to url: \"${request.url}\" failed", exc)
|
||||
retryableExc = true
|
||||
}
|
||||
|
||||
if ((retryableExc) || (shouldRetry(response))) {
|
||||
if (request.retries >= this.maxRetries) {
|
||||
logger.error("Giving up on \"POST\" to url: \"${request.url}\" " +
|
||||
"after ${request.retries} retries")
|
||||
return false
|
||||
}
|
||||
request.retries = (request.retries + 1)
|
||||
backoffSleep(request.retries)
|
||||
return this.publish(request)
|
||||
}
|
||||
|
||||
logger.debug("\"POST\" to url: \"${request.url}\" succeeded")
|
||||
return true
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether this response meets our criteria for retry
|
||||
*/
|
||||
Boolean shouldRetry(Response response) {
|
||||
if (response == null) {
|
||||
return true
|
||||
}
|
||||
|
||||
/* Enhance your calm and try again */
|
||||
if (response.status == 420) {
|
||||
return true
|
||||
}
|
||||
|
||||
/* All server side errors we'll attempt to retry */
|
||||
if ((response.status >= 500) &&
|
||||
(response.status < 600)) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
/**
|
||||
* Sleep the current thread the appropriate amount of time for the
|
||||
* attemptNumber
|
||||
*/
|
||||
void backoffSleep(Long attemptNumber) {
|
||||
int naptime = DEFAULT_BACKOFF_MILLIS ** attemptNumber
|
||||
if (naptime > DEFAULT_BACKOFF_MAX_MILLIS) {
|
||||
naptime = DEFAULT_BACKOFF_MAX_MILLIS
|
||||
}
|
||||
Thread.sleep(naptime)
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the JerseyInvocation instance needed to execute the webhook
|
||||
*/
|
||||
private Invocation buildInvocationFrom(HookRequest request) {
|
||||
return jerseyClient.target(request.url)
|
||||
.request()
|
||||
.buildPost(Entity.entity(request.postData,
|
||||
request.contentType? request.contentType: DEFAULT_CONTENT_TYPE))
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,116 @@
|
|||
package com.github.lookout.whoas;
|
||||
|
||||
import javax.ws.rs.client.Client;
|
||||
import javax.ws.rs.client.ClientBuilder;
|
||||
import javax.ws.rs.client.Entity;
|
||||
import javax.ws.rs.client.Invocation;
|
||||
import javax.ws.rs.core.Response;
|
||||
import javax.ws.rs.ProcessingException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
|
||||
/**
|
||||
* Publisher is the class responsible for implementing the *actual* HTTP
|
||||
* request logic for Whoas
|
||||
*/
|
||||
public class Publisher {
|
||||
private final String DEFAULT_CONTENT_TYPE = "application/json";
|
||||
/** Maximum number of failures we will retry on */
|
||||
private final int DEFAULT_MAX_RETRIES = 5;
|
||||
|
||||
private final int DEFAULT_BACKOFF_MILLIS = 50;
|
||||
private final int DEFAULT_BACKOFF_MAX_MILLIS = (10 * 1000);
|
||||
|
||||
private Client jerseyClient;
|
||||
private int maxRetries;
|
||||
private Logger logger = LoggerFactory.getLogger(Publisher.class);
|
||||
|
||||
public Publisher() {
|
||||
this.jerseyClient = ClientBuilder.newClient();
|
||||
this.maxRetries = DEFAULT_MAX_RETRIES;
|
||||
}
|
||||
|
||||
/**
|
||||
* Publish the request using the appropriate backoff and retry logic
|
||||
* defined in the Whoas documentation
|
||||
*/
|
||||
public Boolean publish(HookRequest request) throws InterruptedException {
|
||||
Response response = null;
|
||||
Boolean retryableExc = false;
|
||||
Invocation inv = buildInvocationFrom(request);
|
||||
|
||||
try {
|
||||
response = inv.invoke();
|
||||
String responseBody = response.readEntity(String.class);
|
||||
}
|
||||
catch (ProcessingException exc) {
|
||||
logger.warn("\"POST\" to url: \"${request.url}\" failed", exc);
|
||||
retryableExc = true;
|
||||
}
|
||||
|
||||
if ((retryableExc) || (shouldRetry(response))) {
|
||||
if (request.retries >= this.maxRetries) {
|
||||
logger.error("Giving up on \"POST\" to url: \"${request.url}\" " +
|
||||
"after ${request.retries} retries");
|
||||
return false;
|
||||
}
|
||||
request.retries = (request.retries + 1);
|
||||
backoffSleep(request.retries);
|
||||
return this.publish(request);
|
||||
}
|
||||
|
||||
logger.debug("\"POST\" to url: \"${request.url}\" succeeded");
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine whether this response meets our criteria for retry
|
||||
*/
|
||||
public Boolean shouldRetry(Response response) {
|
||||
if (response == null) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Enhance your calm and try again */
|
||||
if (response.getStatus() == 420) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/* All server side errors we'll attempt to retry */
|
||||
if ((response.getStatus() >= 500) &&
|
||||
(response.getStatus() < 600)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sleep the current thread the appropriate amount of time for the
|
||||
* attemptNumber
|
||||
*/
|
||||
void backoffSleep(Long attemptNumber) throws InterruptedException {
|
||||
int naptime = (int)(Math.pow(DEFAULT_BACKOFF_MILLIS, attemptNumber));
|
||||
if (naptime > DEFAULT_BACKOFF_MAX_MILLIS) {
|
||||
naptime = DEFAULT_BACKOFF_MAX_MILLIS;
|
||||
}
|
||||
Thread.sleep(naptime);
|
||||
}
|
||||
|
||||
/**
|
||||
* Build the JerseyInvocation instance needed to execute the webhook
|
||||
*/
|
||||
private Invocation buildInvocationFrom(HookRequest request) {
|
||||
String contentType = DEFAULT_CONTENT_TYPE;
|
||||
|
||||
if ((request.contentType != null) &&
|
||||
(!request.contentType.isEmpty())) {
|
||||
contentType = request.contentType;
|
||||
}
|
||||
|
||||
return jerseyClient.target(request.url)
|
||||
.request()
|
||||
.buildPost(Entity.entity(request.postData, contentType));
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue