I'm pretty new to Scala, the Play Framework and Akka. In the project I currently work on, the user of the web application should be able to ask the server several things to do (like starting a particular computation) in an asynchronous way. If the server is done it should notify the user also async. I solve this demand by a WebSocket connection which is established when the user first connects with the Application and the WebSocket is handled by a UserActor, which is attached to the User Session:
def ws = WebSocket.tryAcceptWithActor[JsValue, JsValue] { implicit request =>
Future.successful(request.session.get(UID) match {
case None => Left(Forbidden)
case Some(uid) => Logger.info("WebSocket has accepted the request with uid " + uid)
Right(UserActor.props(uid))
})
}
Currently, the only thing the UserActor does is receiving messages from the WebSocket as JsValue. The UID of the session is generated when requesting index:
def index = Action { implicit request => {
val uid = request.session.get(UID).getOrElse {
counter += 1
counter.toString
}
Ok(views.html.index(uid)).withSession {
Logger.debug("create uid " + uid)
request.session + (UID -> uid)
}}
}
The UserActor should represent the actual user on the Server and thus include the logic of all actions that the user can perform on the Server. This works fine as long as I send all user interaction over the WebSocket.
Now what is the case with other user input, like form submission? The application includes a form whose data should not go over the WebSocket, but rather be submitted with a POST request (perhaps with AJAX) and bound in a controller to the Model like described in the documentation.
def saveContact = Action { implicit request =>
contactForm.bindFromRequest.fold(
formWithErrors => {
BadRequest(views.html.contact.form(formWithErrors))
},
contact => {
val contactId = Contact.save(contact)
Redirect(routes.Application.showContact(contactId)).flashing("success" -> "Contact saved!")
}
)
}
This example is taken from the Playframework documentation.
Now, how do I link the Form Submission handler with the UserActor? Say I want to tell the user actor that a form has been submitted. A trivial example would be that the UserActor sends one value of the form back over the WebSocket to the client as soon it is received. So basically the problem reduces to the issue that I want to send the UserActor Messages from any Controller.
I might come up with the idea to send all form data over the WebSocket, but I also want to realize the upload of large data in the future, which I want to tackle like described in this blog post. Then one scenario I could imagine is that the UserActor should be messaged for each chunk it receives.
I guess one problem is that the UserActor and the WebSocketActor are the same and I rather should split their logic, such that the UserActor is only associated with the Session, but I have no idea how to accomplish this. Maybe I need another actor, say a UserManager, which keeps track of present UserActors and enables access to UserActors?
Do you have any suggestions, recommendations or perhaps an example application which also deals with this case? Thank you very much in advance.
Best regards
Don't use the actor that you pass to tryAcceptWithActor as a representation of the User. It should represent a particular session with that user. Possibly, one of many concurrent sessions (multiple browsers, or tabs) a user could have open at a particular time.
Create a separate actor to represent the user and all of the actions it can perform. Now the session actors should forward their messages to the user actor. Traditional controller methods can also forward requests to the corresponding user actors.
Related
The question assumes the use of Event Sourcing.
When rebuilding current state by replaying events, event handlers should be idempotent. For example, when a user successfully updates their username, a UsernameUpdated event might be emitted, the event containing a newUsername string property. When rebuilding current state, the appropriate event handler receives the UsernameUpdated event and sets the username property on the User object to the newUsername property of the UsernameUpdated event object. In other words, the handling of the same message multiple times always yields the same result.
However, how does such an event handler work when integrating with external services? For example, if the user wants to reset their password, the User object might emit a PasswordResetRequested event, which is handled by a portion of code that issues a 3rd party with a command to send an SMS. Now when the application is rebuilt, we do NOT want to re-send this SMS. How is this situation best avoided?
There are two messages involved in the interaction: commands and events.
I do not regard the system messages in a messaging infrastructure the same as domain events. Command message handling should be idempotent. Event handlers typically would not need to be.
In your scenario I could tell the aggregate root 100 times to update the user name:
public UserNameChanged ChangeUserName(string username, IServiceBus serviceBus)
{
if (_username.Equals(username))
{
return null;
}
serviceBus.Send(new SendEMailCommand(*data*));
return On(new UserNameChanged{ Username = userName});
}
public UserNameChanged On(UserNameChanged #event)
{
_username = #event.UserName;
return #event;
}
The above code would result in a single event so reconstituting it would not produce any duplicate processing. Even if we had 100 UserNameChanged events the result would still be the same as the On method does not perform any processing. I guess the point to remember is that the command side does all the real work and the event side is used only to change the state of the object.
The above isn't necessarily how I would implement the messaging but it does demonstrate the concept.
I think you are mixing two separate concepts here. The first is reconstructing an object where the handlers are all internal methods of the entity itself. Sample code from Axon framework
public class MyAggregateRoot extends AbstractAnnotatedAggregateRoot {
#AggregateIdentifier
private String aggregateIdentifier;
private String someProperty;
public MyAggregateRoot(String id) {
apply(new MyAggregateCreatedEvent(id));
}
// constructor needed for reconstruction
protected MyAggregateRoot() {
}
#EventSourcingHandler
private void handleMyAggregateCreatedEvent(MyAggregateCreatedEvent event) {
// make sure identifier is always initialized properly
this.aggregateIdentifier = event.getMyAggregateIdentifier();
// do something with someProperty
}
}
Surely you wouldn't put code that talks to an external API inside an aggregate's method.
The second is replaying events on a bounded context which could cause the problem you are talking about and depending on your case you may need to divide your event handlers into clusters.
See Axon frameworks documentation for this point to get a better understanding of the problem and the solution they went with.
Replaying Events on a Cluster
TLDR; store the SMS identifier within the event itself.
A core principle of event sourcing is "idempotency". Events are idempotent, meaning that processing them multiple times will have the same result as if they were processed once. Commands are "non-idempotent", meaning that the re-execution of a command may have a different result for each execution.
The fact that aggregates are identified by UUID (with a very low percentage of duplication) means that the client can generate the UUIDs of newly created aggregates. Process managers (a.k.a., "Sagas") coordinate actions across multiple aggregates by listening to events in order to issue commands, so in this sense, the process manager is also a "client". Cecause the process manager issues commands, it cannot be considered "idempotent".
One solution I came up with is to include the UUID of the soon-to-be-created SMS in the PasswordResetRequested event. This allows the process manager to only create the SMS if it does not yet already exist, hence achieving idempotency.
Sample code below (C++ pseudo-code):
// The event indicating a password reset was successfully requested.
class PasswordResetRequested : public Event {
public:
PasswordResetRequested(const Uuid& userUuid, const Uuid& smsUuid, const std::string& passwordResetCode);
const Uuid userUuid;
const Uuid smsUuid;
const std::string passwordResetCode;
};
// The user aggregate root.
class User {
public:
PasswordResetRequested requestPasswordReset() {
// Realistically, the password reset functionality would have it's own class
// with functionality like checking request timestamps, generationg of the random
// code, etc.
Uuid smsUuid = Uuid::random();
passwordResetCode_ = generateRandomString();
return PasswordResetRequested(userUuid_, smsUuid, passwordResetCode_);
}
private:
Uuid userUuid_;
string passwordResetCode_;
};
// The process manager (aka, "saga") for handling password resets.
class PasswordResetProcessManager {
public:
void on(const PasswordResetRequested& event) {
if (!smsRepository_.hasSms(event.smsUuid)) {
smsRepository_.queueSms(event.smsUuid, "Your password reset code is: " + event.passwordResetCode);
}
}
};
There are a few things to note about the above solution:
Firstly, while there is a (very) low possibility that the SMS UUIDs can conflict, it can actually happen, which could cause several issues.
Communication with the external service is prevented. For example, if user "bob" requests a password reset that generates an SMS UUID of "1234", then (perhaps 2 years later) user "frank" requests a password reset that generates the same SMS UUID of "1234", the process manager will not queue the SMS because it thinks it already exists, so frank will never see it.
Incorrect reporting in the read model. Because there is a duplicate UUID, the read side may display the SMS sent to "bob" when "frank" is viewing the list of SMSes the system sent him. If the duplicate UUIDs were generated in quick succession, it is possible that "frank" would be able to reset "bob"s password.
Secondly, moving the SMS UUID generation into the event means you must make the User aggregate aware of the PasswordResetProcessManager's functionality (but not the PasswordResetManager itself), which increases coupling. However, the coupling here is loose, in that the User is unaware of how to queue an SMS, only that an SMS should be queued. If the User class were to send the SMS itself, you could run into the situation in which the SmsQueued event is stored while the PasswordResetRequested event is not, meaning that the user will receive an SMS but the generated password reset code was not saved on the user, and so entering the code will not reset the password.
Thirdly, if a PasswordResetRequested event is generated but the system crashes before the PasswordResetProcessManager can create the SMS, then the SMS will eventually be sent, but only when the PasswordResetRequested event is re-played (which might be a long time in the future). E.g., the "eventual" part of eventual consistency could be a long time away.
The above approach works (and I can see that it should also work in more complicated scenarious, like the OrderProcessManager described here: https://msdn.microsoft.com/en-us/library/jj591569.aspx). However, I am very keen to hear what other people think about this approach.
I'm developing an application using Play framework in scala. I have to handle the below use case in my application.
For a particular request from the browser to the play server the Play server should make an http request to some external server (for Eg: somesite.com) and send the response from this request back to the web browser.
I have written the below code to send the request to external serever in the controller.
val holder = WS.url("http://somesite.com")
val futureResponse = holder.get
Now how do I send back the response recieved from "somesite.com" back to the browser?
There's an example in the Play documentation for WS, under Using in a controller; I've adapted it to your scenario:
def showSomeSiteContent = Action.async {
WS.url("http://somesite.com").get().map { response =>
Ok(response.body)
}
}
The key thing to note is the idiomatic use of map() on the Future that you get back from the get call - code inside this map block will be executed once the Future has completed successfully.
The Action.async "wrapper" tells the Play framework that you'll be returning a Future[Response] and that you want it to do the necessary waiting for things to happen, as explained in the Handling Asynchronous Results documentation.
You may also be interested in dynamically returning the status and content type:
def showSomeSiteContent = Action.async {
WS.url("http://somesite.com").get().map { response =>
Status(response.status)(response.body).as(response.ahcResponse.getContentType)
}
}
Dynamic status could help if the URL/service you call fails to answer correctly.
Dynamic content type can be handy if your URL/service can return different content HTML/XML... depending on some dynamic parameter.
I am trying to implement a proof of concept service bus using MassTransit. I have three applications which need to communicate changes of a common entity type between each other. So when the user updates the entity in one application, the other two are notified.
Each application is configured as follows with their own queue:
bus = ServiceBusFactory.New(sbc =>
{
sbc.UseMsmq();
sbc.VerifyMsmqConfiguration();
sbc.ReceiveFrom("msmq://localhost/app1_queue");
sbc.UseSubscriptionService("msmq://localhost/subscription");
sbc.UseControlBus();
sbc.Subscribe(subs =>
{
subs.Handler<IMessage1>(IMessage1_Received);
});
});
There is also a subscription service application configured as follows:
subscriptionBus = ServiceBusFactory.New(sbc =>
{
sbc.UseMsmq();
sbc.VerifyMsmqConfiguration();
sbc.ReceiveFrom("msmq://localhost/subscription");
});
var subscriptionSagas = new InMemorySagaRepository<SubscriptionSaga>();
var subscriptionClientSagas = new InMemorySagaRepository<SubscriptionClientSaga>();
subscriptionService = new SubscriptionService(subscriptionBus, subscriptionSagas, subscriptionClientSagas);
subscriptionService.Start();
The problem is that when one of the applications publishes a message, all three applications receive it (including the original sender).
Is there any way to avoid this (without resorting to adding the application name to the message)?
Thanks,
G
So MassTransit is a pub/sub system. If you publish a message, everyone registered to receive it will. If you need only some endpoints to receive it, then you really need to directly send. It's just how this works.
You could include the source in your message and discard messages that aren't of interest to you. If you implement the Consumes.Accept interface, I think the Accept method would allow you to do so easily without mixing that into the normal consumption code.
My web application will be triggered from an external system. It will call one request path of my app, but uses different query parameters for different kinds of requests.
One of the parameters is the "action" that defines what is to be done. The rest of the params depend on the "action".
So I can get request params like these:
action=sayHello&user=Joe
action=newUser&name=Joe&address=xxx
action=resetPassword
...
I would like to be able to encode it similarly in the routes file for play so it does the query param based routing and as much of the validation of other parameters as possible.
What I have instead is one routing for all of these possibilities with plenty of optional parameters. The action processing it starts with a big pattern match to do dispatch and parameter validation.
Googling and checking SO just popped up plenty of samples where the params are encoded in the request path somehow, so multiple paths are routed to the same action, but I would like the opposite: one path routed to different actions.
One of my colleagues said we could have one "dispatcher" action that would just redirect based on the "action" parameter. It would be a bit more structured then the current solution, but it would not eliminate the long list of optional parameters which should be selectively passed to the next action, so I hope one knows an even better solution :-)
BTW the external system that calls my app is developed by another company and I have no influence on this design, so it's not an option to change the way how my app is triggered.
The single dispatcher action is probably the way to go, and you don't need to specify all of your optional parameters in the route. If action is always there then that's the only one you really need.
GET /someRoute controller.dispatcher(action: String)
Then in your action method you can access request.queryString to get any of the other optional parameters.
Note: I am NOT experienced Scala developer, so maybe presented snippets can be optimized... What's important for you they are valid and working.
So...
You don't need to declare every optional param in the routes file. It is great shortcut for type param's validation and best choice would be convince 'other company' to use API prepared by you... Anyway if you haven't such possibility you can also handle their requests as required.
In general: the dispatcher approach seems to be right in this place, fortunately you don't need to declare all optional params in the routes and pass it between actions/methods as they can be fetched directly from request. In PHP it can be compared to $_GET['action'] and in Java version of Play 2 controller - DynamicForm class - form().bindFromRequest.get("action").
Let's say that you have a route:
GET /dispatcher controllers.Application.dispatcher
In that case your dispatcher action (and additional methods) can look like:
def dispatcher = Action { implicit request =>
request.queryString.get("action").flatMap(_.headOption).getOrElse("invalid") match {
case "sayHello" => sayHelloMethod
case "newUser" => newUserMethod
case _ => BadRequest("Action not allowed!")
}
}
// http://localhost:9000/dispatcher?action=sayHello&name=John
def sayHelloMethod(implicit request: RequestHeader) = {
val name = request.queryString.get("name").flatMap(_.headOption).getOrElse("")
Ok("Hello " + name )
}
// http://localhost:9000/dispatcher?action=newUser&name=John+Doe&address=john#doe.com
def newUserMethod(implicit request: RequestHeader) = {
val name = request.queryString.get("name").flatMap(_.headOption).getOrElse("")
val address = request.queryString.get("address").flatMap(_.headOption).getOrElse("")
Ok("We are creating new user " + name + " with address " + address)
}
Of course you will need to validate incoming types and values 'manually', especially when actions will be operating on the DataBase, anyway biggest part of your problem you have resolved now.
Action create shows form:
def create = Action {
Ok(html.post.create(postForm))
}
How can i modify this action so that for GET request it would give out form and for the POST request it would process user input data, as if it were a separate action:
def newPost = Action { implicit request =>
postForm.bindFromRequest.fold(
errors => BadRequest(views.html.index(Posts.all(), errors)),
label => {
Posts.create(label)
Redirect(routes.Application.posts)
}
)
}
Wthat i mean is i want to combine this two actions.
UPDATE1: I want a single Action that serves GET and POST requests
It is recommended not to merge both actions, but modify routes to get the behavior you are expecting. For instance:
GET /create controllers.Posts.create
POST /create controllers.Posts.newPost
In case you have several kind of resources (post and comments, for instance), just add
a prefix to the path to disambiguate:
GET /post/create controllers.Posts.create
POST /post/create controllers.Posts.newPost
GET /comment/create controllers.Comments.create
POST /comment/create controllers.Comments.newComment
I tried once to accomplish similar thing, but I realized that I wasn't using framework like it was meant to be used. Use separate GET and POST methods like #paradigmatic showed and in cases like you specified "If we take adding comments to another action, we wouldn't be able to get infomation on post and comments in case an error occured (avoding copy-paste code)." - just render the page at the end of controller method with the view you like? and for errors etc. you can always use flash scope too? http://www.playframework.org/documentation/2.0.2/ScalaSessionFlash you could also render this form page with two or more beans and send them to controller side to catch related error messages and data.?