Skip to content

Commit

Permalink
SYMPHONYP-940 refactor retry handler
Browse files Browse the repository at this point in the history
  • Loading branch information
vaibhav-db committed Mar 2, 2023
1 parent 3f2fec6 commit a9f3699
Show file tree
Hide file tree
Showing 9 changed files with 133 additions and 62 deletions.
Original file line number Diff line number Diff line change
@@ -1,23 +1,41 @@
package org.finos.springbot.teams;

import java.util.concurrent.TimeUnit;

import org.finos.springbot.teams.handlers.TeamsResponseHandler;
import org.finos.springbot.teams.handlers.retry.NoOpRetryHandler;
import org.finos.springbot.teams.handlers.retry.RetryHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;

import org.springframework.scheduling.annotation.SchedulingConfigurer;
import org.springframework.scheduling.config.ScheduledTaskRegistrar;

@EnableScheduling
public class TeamsScheduledConfig {
public class TeamsScheduledConfig implements SchedulingConfigurer {

private static final Logger LOG = LoggerFactory.getLogger(TeamsScheduledConfig.class);

@Autowired
private TeamsResponseHandler handler;

@Scheduled(fixedDelay = 30, timeUnit = TimeUnit.SECONDS)
//Task to run after a fixed delay.
//the duration between the end of last execution and the start of next execution is fixed
public void scheduleRetryMessage() {

@Autowired
private RetryHandler retryHandler;

@Value("${teams.retry.time:30000}")
private long teamsRetrySchedulerCron;

@Override
public void configureTasks(ScheduledTaskRegistrar scheduledTaskRegistrar) {
if (retryHandler instanceof NoOpRetryHandler) {
LOG.info("No operation retry handler is configure");
} else {
Runnable runnable = () -> scheduleRetryMessage();
scheduledTaskRegistrar.addFixedDelayTask(runnable, teamsRetrySchedulerCron);
}
}

private void scheduleRetryMessage() {
handler.retryMessage();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,10 @@
import org.finos.springbot.teams.conversations.TeamsConversationsConfig;
import org.finos.springbot.teams.form.TeamsFormConverter;
import org.finos.springbot.teams.form.TeamsFormDeserializerModule;
import org.finos.springbot.teams.handlers.InMemoryMessageRetryHandler;
import org.finos.springbot.teams.handlers.MessageRetryHandler;
import org.finos.springbot.teams.handlers.TeamsResponseHandler;
import org.finos.springbot.teams.handlers.retry.InMemoryMessageRetryHandler;
import org.finos.springbot.teams.handlers.retry.NoOpRetryHandler;
import org.finos.springbot.teams.handlers.retry.RetryHandler;
import org.finos.springbot.teams.history.StateStorageBasedTeamsHistory;
import org.finos.springbot.teams.history.StorageIDResponseHandler;
import org.finos.springbot.teams.history.TeamsHistory;
Expand Down Expand Up @@ -130,7 +131,7 @@ public TeamsResponseHandler teamsResponseHandler(
ThymeleafTemplateProvider displayTemplater,
TeamsStateStorage th,
TeamsConversations tc,
MessageRetryHandler mr) {
RetryHandler mr) {
return new TeamsResponseHandler(
null, // attachment handler
markupTemplater,
Expand Down Expand Up @@ -230,9 +231,13 @@ public void setResourceLoaderClassLoader() {
resourceLoader.setClassLoader(this.getClass().getClassLoader());
}

/**
* set NoOpRetryHandler() if you don't want rety
* @return
*/
@Bean
@ConditionalOnMissingBean
public MessageRetryHandler messageRetryHandler() {
public RetryHandler messageRetryHandler() {
return new InMemoryMessageRetryHandler();
}

Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,11 @@
import java.util.concurrent.CompletionException;
import java.util.function.BiFunction;

import org.apache.commons.lang3.StringUtils;
import org.finos.springbot.teams.TeamsException;
import org.finos.springbot.teams.content.TeamsAddressable;
import org.finos.springbot.teams.conversations.TeamsConversations;
import org.finos.springbot.teams.handlers.retry.MessageRetry;
import org.finos.springbot.teams.handlers.retry.RetryHandler;
import org.finos.springbot.teams.history.StorageIDResponseHandler;
import org.finos.springbot.teams.history.TeamsHistory;
import org.finos.springbot.teams.response.templating.EntityMarkupTemplateProvider;
Expand All @@ -32,7 +33,6 @@
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.http.HttpStatus;
import org.springframework.util.ErrorHandler;

import com.fasterxml.jackson.core.JsonProcessingException;
Expand All @@ -46,13 +46,11 @@
import com.microsoft.bot.schema.ResourceResponse;
import com.microsoft.bot.schema.TextFormatTypes;

import okhttp3.ResponseBody;

public class TeamsResponseHandler implements ResponseHandler, ApplicationContextAware {

private static final Logger LOG = LoggerFactory.getLogger(TeamsResponseHandler.class);

private static final int RETRY_COUNT = 3;

private static final int INIT_RETRY_COUNT = 0;

protected AttachmentHandler attachmentHandler;
Expand All @@ -63,7 +61,7 @@ public class TeamsResponseHandler implements ResponseHandler, ApplicationContext
protected ThymeleafTemplateProvider displayTemplater;
protected TeamsStateStorage teamsState;
protected TeamsConversations teamsConversations;
protected MessageRetryHandler messageRetryHandler;
protected RetryHandler retryHandler;

public TeamsResponseHandler(
AttachmentHandler attachmentHandler,
Expand All @@ -72,14 +70,14 @@ public TeamsResponseHandler(
ThymeleafTemplateProvider displayTemplater,
TeamsStateStorage th,
TeamsConversations tc,
MessageRetryHandler mr) {
RetryHandler mr) {
this.attachmentHandler = attachmentHandler;
this.messageTemplater = messageTemplater;
this.workTemplater = workTemplater;
this.displayTemplater = displayTemplater;
this.teamsState = th;
this.teamsConversations = tc;
this.messageRetryHandler = mr;
this.retryHandler = mr;
}

protected void initErrorHandler() {
Expand All @@ -95,7 +93,7 @@ public void accept(Response t) {
sendResponse(t, INIT_RETRY_COUNT);
}

private void sendResponse(Response t, int retryCount) {
public void sendResponse(Response t, int retryCount) {
if (t.getAddress() instanceof TeamsAddressable) {
TeamsAddressable ta = (TeamsAddressable) t.getAddress();

Expand Down Expand Up @@ -192,32 +190,10 @@ private BiFunction<? super ResourceResponse, Throwable, ResourceResponse> handle
};
}

private boolean insertIntoQueue(Response t, int retryCount, Throwable e) {
if (e instanceof CompletionException
&& ((CompletionException) e).getCause() instanceof ErrorResponseException) {
ErrorResponseException ere = (ErrorResponseException) ((CompletionException) e).getCause();
retrofit2.Response<ResponseBody> response = ere.response();
if (response.code() == HttpStatus.TOO_MANY_REQUESTS.value() && retryCount <= RETRY_COUNT) {
String retryAfter = response.headers().get("Retry-After");

int retryAfterInt = 1;//initiate to 1 sec
if(StringUtils.isNumeric(retryAfter)) {
retryAfterInt = Integer.parseInt(retryAfter);
}

messageRetryHandler.add(new MessageRetry(t, retryCount, retryAfterInt));

return true;
}
}

return false;
}

private BiFunction<? super ResourceResponse, Throwable, ResourceResponse> handleErrorAndStorage(Object out, TeamsAddressable address, Map<String, Object> data, Response t, int retryCount) {
return (rr, e) -> {
if (e != null) {
boolean success = insertIntoQueue(t, retryCount, e);
boolean success = retryHandler.handleException(t, retryCount, e);
if(!success) {
LOG.error(e.getMessage());
if (out instanceof ObjectNode){
Expand All @@ -239,7 +215,7 @@ private BiFunction<? super ResourceResponse, Throwable, ResourceResponse> handle
return null;
};
}

protected CompletableFuture<ResourceResponse> sendCardResponse(JsonNode json, TeamsAddressable address, Map<String, Object> data) throws Exception {
Activity out = Activity.createMessageActivity();
Attachment body = new Attachment();
Expand Down Expand Up @@ -275,7 +251,7 @@ public void retryMessage() {
int messageCount = 0;

Optional<MessageRetry> opt;
while ((opt = messageRetryHandler.get()).isPresent()) {
while ((opt = retryHandler.get()).isPresent()) {
messageCount++;
this.sendResponse(opt.get().getResponse(), opt.get().getRetryCount());
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.finos.springbot.teams.handlers;
package org.finos.springbot.teams.handlers.retry;

import java.time.LocalDateTime;
import java.util.Optional;
Expand All @@ -8,7 +8,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

public class InMemoryMessageRetryHandler implements MessageRetryHandler {
public class InMemoryMessageRetryHandler extends MessageRetryHandler {

private static final Logger LOG = LoggerFactory.getLogger(InMemoryMessageRetryHandler.class);

Expand All @@ -34,5 +34,6 @@ public Optional<MessageRetry> get() {

return Optional.empty();
}


}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package org.finos.springbot.teams.handlers;
package org.finos.springbot.teams.handlers.retry;

import java.time.LocalDateTime;

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
package org.finos.springbot.teams.handlers.retry;

import java.util.concurrent.CompletionException;

import org.apache.commons.lang3.StringUtils;
import org.finos.springbot.workflow.response.Response;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;

import com.microsoft.bot.connector.rest.ErrorResponseException;

import okhttp3.ResponseBody;

public abstract class MessageRetryHandler implements RetryHandler {

private static final Logger LOG = LoggerFactory.getLogger(MessageRetryHandler.class);

@Value("${teams.retry.count:3}")
private long teamsRetryCount;

public boolean handleException(Response t, int retryCount, Throwable e) {
if (e instanceof CompletionException
&& ((CompletionException) e).getCause() instanceof ErrorResponseException) {
ErrorResponseException ere = (ErrorResponseException) ((CompletionException) e).getCause();
retrofit2.Response<ResponseBody> response = ere.response();
if (response.code() == HttpStatus.TOO_MANY_REQUESTS.value() && retryCount <= teamsRetryCount) {
String retryAfter = response.headers().get("Retry-After");
LOG.info("MessageRetryHandler request retryAfter {}", retryAfter);

int retryAfterInt = 1;//initiate to 1 sec
if(StringUtils.isNumeric(retryAfter)) {
retryAfterInt = Integer.parseInt(retryAfter);
}

add(new MessageRetry(t, retryCount, retryAfterInt));

return true;
}
}

return false;
}

protected abstract void add(MessageRetry messageRetry);


}
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package org.finos.springbot.teams.handlers.retry;

import java.util.Optional;

import org.finos.springbot.workflow.response.Response;

public class NoOpRetryHandler implements RetryHandler {

@Override
public Optional<MessageRetry> get() {
return Optional.empty();
}

@Override
public boolean handleException(Response t, int retryCount, Throwable e) {

return false;
}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
package org.finos.springbot.teams.handlers.retry;

import java.util.Optional;

import org.finos.springbot.workflow.response.Response;

public interface RetryHandler {

public boolean handleException(Response t, int retryCount, Throwable e);

public Optional<MessageRetry> get();

}

0 comments on commit a9f3699

Please sign in to comment.