Como executar a inserção assíncrona do banco de dados no método onReceive do Actor?
-
21-12-2019 - |
Pergunta
Eu tenho um aplicativo Play Framework 2 que também usa Akka.eu tenho um Actor
que recebe mensagens de um sistema remoto, a quantidade dessas mensagens pode ser muito grande.Depois que uma mensagem é recebida, eu a registro no banco de dados (usando o Ebean ORM integrado) e continuo a processá-la.Eu não me importo com a rapidez com que esse registro de banco de dados funciona, mas definitivamente não deve bloquear o processamento posterior.Aqui está um exemplo de código simplificado:
public class MessageReceiver extends UntypedActor {
@Override
public void onReceive(Object message) throws Exception {
if (message instanceof ServerMessage) {
ServerMessage serverMessage = (ServerMessage) message;
ServerMessageModel serverMessageModel = new ServerMessageModel(serverMessage);
serverMessageModel.save();
//now send the message to another actor for further processing
} else {
unhandled(message);
}
}
}
Pelo que entendi, a inserção do banco de dados está bloqueando essa realização, portanto não atende às minhas necessidades.Mas não consigo descobrir como desbloqueá-lo.Eu li sobre o Future
class, mas não consigo fazê-lo funcionar, pois deve retornar algum valor, e serverMessageModel.save();
retorna void
Entendo que escrever muitas mensagens, uma por uma, no banco de dados é ineficiente, mas esse não é o problema no momento.
Estou certo de que esta implementação está bloqueando?Se for, como posso fazê-lo funcionar de forma assíncrona?
Solução
Se você deseja usar Future - construa um Akka Future com um Callable (classe anônima), cujo apply() irá realmente implementar o código de salvamento do banco de dados.Na verdade, você pode colocar tudo isso (criação futura e aplicação ()) em sua classe ServerMessageModel - talvez chame-a de asynchSave ().Seu Futuro talvez Futuro onde o status é o resultado de asynchSave...
public Future<Status> asyncSave(...) { /* should the params be ServerMessageModel? */
return future(new Callable<Status>() {
public Status call() {
/* do db work here */
}
}
No seu onReceive você pode contar ao outro ator.OBSERVAÇÃO:se você quiser ter certeza de que está disparando o comando para o outro ator após o retorno desse futuro, você pode usar o onSuccess do Future.
Future<Status> f = serverMessageModel.asyncSave();
f.onSuccess(otherActor.tell(serverMessage, self());
Você também pode lidar com falhas ...ver http://doc.akka.io/docs/akka/2.3.4/java/futures.html para mais detalhes.
Espero que ajude.
Outras dicas
A solução futura parece boa para mim.Não usei Futures de Java, mas você pode retornar um número inteiro ou string arbitrário se definitivamente precisar de algum valor de retorno.
Outra opção é enviar essa mensagem para algum outro ator que faria o salvamento no banco de dados.Então você deve certificar-se de que a caixa de correio desse ator não fique lotada.
Você considerou akka-persistência por esta?Talvez isso seja adequado ao seu caso de uso.
Persista o estado do ator com a extensão akka-persistence de Martin Krasser e meu provedor de persistência jdbc akka persistence jdbc https://github.com/dnvriend/akka-persistence-jdbc