Say we want to make an application containing the following:
Asynchronous and time consuming operations on selected objects
For a certain object we want to access the status of an associated operation.
The ability to show, cancel and pause these operations from multiple views.
Then my question is the following:
Where do these operations and their progress/status belong in an Application Design Pattern?
To put it into context here is a dummy application:
Example Application:
We have an application where you can apply different Filters to Images. Application consists of a Directory View and Detail View.
Each filter can be applied asynchronously to any image from each view.
The filter-operation can be observed and canceled from both views.
A filter operation can not be started if there is already one initiated for that filter-type and image, or if such a filter has already produced a result.
In this dummy application the views are subsequent, but in the general case you would not be able to pass information directly between the views.
Progress
Decoupling the Service Layer or Network Controller from the View and Model in a design pattern like MVC or MVVM is quite straight forward, as long as you don't provide more UX feedback than a spinner when there's an active network request.
But when I am working on an application confirming to the criteria above, I always end up either
Not allowing the user to change view during an operation
Tagging operations with the id of the object currently processed and passing this to the views, or looking in the Network Controller directly from the views/view controllers
Creating a separate entities for operations, and suddenly I have a request operation in my model
So obviously there are (very smelly) ways to come around this, but they all feel dirty and not inline with how the patterns are intended.
So purely from a software architecture and design pattern point of view, how would you approaching this?
I generally prefer a promise object for this design issue. The promise object can contain methods to cancel the operation, check on the status of the operation and even contain closures to be executed depending on what happens with the operation (success, failure, cancel, etc.).
That promise object can either be handed from view to view or can be served from the network layer upon multiple requests (view A kicks off operation, view B tries later to kick it off but it is already running so gets the same promise object).
That means that the service layer, or network layer in this case, needs to present which operations, requests, are ongoing for which object, right? Because you don't want to kick of a request just to get the promise object, in case a button should be hidden if the operation is already started. I guess you would keep these promise objects outside your app model since they don't live between sessions, and the network layer would store them by url, but how would you generally serve this back from the network layer without exposing to much the network layer to the ui?
Network layer has convenience methods for the UI to utilize to kick off requests that the user initiates. The network layer determines if a request has already started and returns the same promise. Even if the network layer kicked off the process internally (auto refresh, etc) it can still deliver the promise back to the UI if the UI tries to start the same process.
The promise objects only live as long as the operation is on-going. I actually have the operation be the true holder of the promise object and the network controller holds the queue of operations. Then when a request comes in, I search the queue for the existence of that operation and if it exists return the promise from the operation. If it doesn't exist, I create a new operation, put it in the queue and return its promise object.
The interface between the UI and the back end is the exposed methods on the network controller. The UI has no knowledge of operations, it just has a function that says "go refresh this or go get that" and gets a promise back. It does not need to know or care how the job is performed, it just knows that the promise is its way to check on the status of that operation.
Now, if it is a data refresh, then the promise isn't needed for data updates, the NSFetchedResultsController will handle that. The promise in that situation handles "am I active" and "cancel me" type requests only.
There will be many ways to do this. But here's an idea... Maybe you can use messaging as style: define a "status" channel, possibly use a pub-sub model for getting the status/progress of on-going operations. So that way, the process performing the operations publishes the status on a channel, and your multiple views subscribe to that channel and display the status. Now, if you have to cancel/pause operations, you possibly need to have another control channel. You do have to manage concurrency, order etc.
Related
I have some complex networking in my app( I don't use any third party dependencies, because of project requirements). For instance, I send three network requests in parallel after first two requests provide results. All my networking is done in separate models, known as networkClients(following MVC-S pattern) and are called directly from repository, not from ViewControllers. However, I need the last request to notify my viewController after I get response from network. How should I do that? I don't think notification center would be right solution because it can cause memory leaks and I have not found correct approach to complex problem like this. Please provide some prominent solutions. It should conform to good design pattern like MVVM or MVC and should not be some workaround or hack. Maybe delegates would work? I know that rxSwift would solve my issue, because I could start observing for results after initializing viewController and after data would be updated from repository my viewController would also be notified...
The right design doesn't have VCs observing the network clients directly. Those network operations should be assembling parts of a model, which is what the VC really cares about. Have the VC observe that singular model.
It can do this observing using one of the well known patterns for loosely coupled communication between objects. The OP correctly mentions delegates. Notification center and KVO are others. There's plenty of discussion on SO about which to use and how to implement. (I'd go with NSNotificationCenter as an easy and rational start).
So the order of operation is like this:
allocate the model
launch the network requests and setup those request completions (completion blocks, probably) to update that model with their responses. (the model can launch the requests, which is a reasonable practice).
create the view controller(s) that setup model observation when they initialize (probably, in viewWillAppear or later)
What about the fact that >1 requests are in flight simultaneously? A commenter above points out correctly that GCD offers a way to group those async operations into a single one. But you can do this yourself straight-forwardly: the model decides when it's completely built. The completion code for each request will change some condition in the model to the "ready" state. Each request completion can check to see whether all of the ready conditions are met, and only then post a "ready" notification for observers to see.
Another niggling issue: what if those requests all run very, very fast? Maybe there's some cached response that's ready early, making the model "ready" before the VC has had a chance to setup observation? Handle this straight-forwardly in the VC: before observing the model, check to see if it's ready already and run the same update code that runs on the notification.
An app I am working on requires creating a container object on a server and inserting items into that container. I don't want to create the container object until the first item needs to be inserted. However, creating the container object requires some initialization that may take a little time. While that container is still initializing the user can still to send insertion requests that aren't getting handled because the container isn't ready yet. I have two main questions:
Should this be dealt with on the client or server side?
What is the best practice for dealing with kind of this issue?
Essentially, I need to ensure my initial createContainer data task in complete before any insertItem requests are sent.
Addition Information
An insertItem request is sent by clicking on a corresponding tableViewCell. The first tableViewCell a user clicks on sends a createContainer request that creates a container holding the first item.
For a container holding n items, the request should be sent in the following order:
createContainer(Container(with: item1)
insertItem(item2)
...
insertItem(itemn)
After the first request completes, the remaining n – 1 requests may complete in any order.
My Thoughts
It sounds like I want the createContainer request to be handled synchronously while the insertItem request should be handled asynchronously. I'm not sure if that is the best approach or even how to perform that appropriately, so any guidance would be greatly appreciated.
You can use a NSOperationQueue and multiple NSOperations to implement your desired behavior. A NSOperation instance can be dependent on the completion of another NSOperation instance:
dependencies
An array of the operation objects that must finish
executing before the current object can begin executing.
For your example this would mean that the insertItem-Operations are dependent on the createContainer operation.
When you add all those operations to a NSOperationQueue your createContainer operation will run first. When it has finished, the other operations will start running as their dependencies are now satisfied. You can also control how many operations you want to run concurrently using maxConcurrentOperationCount on NSOperationQueue.
As you will be using asynchronous API in your NSOperations you will need to implement a ConcurrentOperation and handle the state changes yourself. The API Reference is explaining this in pretty good detail.
Check out the API Reference for NSOperation for further information.
There is also a nice NSHipster article on NSOperations.
Adding to the NSOperationQueue answer, it's sometimes difficult to manually manage all the state changes that an NSOperation requires to handle something asynchronous like a network call.
To simplify that, you can use a Swift Library called Overdrive. It's an amazing library in which you simply subclass a Task class and write your network code in the run() function. And when you're done, you simply call self.finish to finish the task. Here's an example: Just create a simple download task:
Then, just add it to the queue.
You can also add dependencies between tasks, which basically solves your use case.
Hope this helps.
Sometimes operations are depending on each other, user can not update record until he inserted it. How can client changes be synchronised / uploaded to server, without blocking the GUI, if user interactions are more frequent than internet communication allows it?
In my recent version of my app, I store changes in Core Data and same time send change to backend, and until success message returns, I block GUI to keep client and server storage in a consistent state. But I know it is not a good approach especially if there is a lot of control in the same GUI, and user could play with them manipulate them quickly with short delays. Because it is annoying, that you have to wait.
What general approach do you recommend to build a responsive app which is not depending and able to hide the relative slowness of internet communication. Any good tutorial about it?
This is a theoretic question, and expecting theoretic answer.
A good way is to have this setup with parent and child managed object contexts:
SavingContext (background, saves to persistent store)
MainContext (main thread, child context of saving context)
WorkerContext (background, child context of main context)
Thanks Marcus Zarra.
UI initiated changes in the model get saved right away in the main context. You then send them to the backend in a spawned worker context. You can have several of these without problem.
Once the response comes from the server, you save the changes in the worker context which "pushes" them up to the main context. Here you can define a merge policy that resolves any conflicts (for details please ask a new question).
The main context can now update the UI with the new information (if any).
I'm learning about the AsyncController in ASP.NET MVC and using it with the TPL, but I'm struggling to see its need, I can understand when you would want to run an Action asynchronously to do something like send out an email, but in reality would you ever use it to return a view from an action?
For example if the Action gets some data from a database, which is set to work async, then return a View, if the data fails to retrieve in time will the View not just return with no data in the model?
Would you ever use it to return a view from an action?
The main advantage of asynchrony in ASP.NET is scalability. While the asynchronous work executes, you're not consuming any threads. This means your application will consume less memory and it may be also faster.
If the data fails to retrieve in time will the View not just return with no data in the model?
That depends on you and how exactly will you handle that failure.
Async controllers are used primarily to give up the current thread pool thread to allow other incoming connections to process work while you are waiting for a long running process to complete.
This has nothing to do with pass a view back. The process will still "block" from the end users perspective, but on the server the resources the server needs to respond to incoming requests will not be consumed.
By default, there are 250 thread pool threads per cpu core in an IIS worker process to respond to incoming connections (this can be tuned, but in general you should know what you're doing). If you have to people waiting for long requests to complete, then nobody else will be able to connect to your server until one of them finishes. Async controllers fix that problem.
You can also offload CPU bound work to a dedicated thread when using async controllers, where that was more difficult in synchronous controllers. And, it allows you to perform tasks in parallel. For instance, suppose you have to go out to 10 web sites and retrieve data. Most of the time is spent waiting for those web requests to return, and they can be done in parallel if you are doing things async.
This question describes two approaches of solving the sophisticated architectural problem related to ASP.NET MVC. Unfortunately our team is quite new to this technology and we haven’t found any solid sources of information on this particular topic (except overviews where it’s said that MVC is more about separation than componentization). So as for now we are hesitating: whether our solution is appropriate or there is a different obvious way to solve this problem.
We have a requirement to make ASP.NET MVC-based design with componentization in mind. View engine Razor is also a requirement for us. The key feature here is that any level of controller’s nesting is expected (obviously thru Html.Action directive within .cshtml). Any controller could potentially obtain the data thru a webservice call (the final design can break this limitation, as it’s described below).
The issue is that the data must be obtained in async and maximum parallel fashion. E.g. if two backend calls within the controllers are independent they must be performed in parallel.
At first glance the usage of async MVC controllers could solve all the problems. But there is a hidden caveat: nested controller must be specified within cshtml only (within a view). And a .cshtml view is being parsed after the original controller finished its own async execution. So all the async operations within the nested controller will be performed in a separate async slot and therefore not in parallel with the first parent controller. This is a limitation of synchronous nature of .cshtml processing.
After a deep investigation we revealed that two options are available.
1) Have only one parent async controller which will retrieve all the data and put this data into container (dictionary or whatever). The nested controllers aren’t allowed to perform any backend calls. Instead of this they will have a reference to the initialized container with the results of all the backend calls. Bu this way the consumer of the framework must differentiate between parent and child controller which is not a brilliant solution.
2) Retrieve all the data from backends within a special async HttpModule. This module will initialize the same container which will reside, for instance within HttpContext. Obviously all the controllers in such a case will not be allowed to perform any backend calls, but they will have a unified internal structure (in comparison with #1 option).
As for now we think that the option #2 is more desirable, but we are more interested in the solid community-adopted way to solve this problem in a real enterprise-level MVC projects.
Literally any links/comments are welcomed.
[UPD] A requirement of any level of nesting of controllers came from our customer which wants a system where fully reusable MVC components will be presented. And they could be combined in any sequence with any level of nesting - as it is already done in the existing webforms-based implementation. This is a business rule for existing app that the components could be combined anyhow so we're not targeted to break this rule. As for now we think that such a component is a combination of "controller+view+metadata" where "metadata" part describes the backend calls to be performed in the scenario 1 or 2.
Why are you considering async calls here? Keep in mind if your async calls are so the asp.net threads don't get all used up since the db is taking a while to return, as soon as new requests come in they too will go to the db, thus increasing the workload and in turn gaining nothing.
To be honest though, Im having a hard time following exactly what you have in mind here. Nested controllers for...?
"The key feature here is that any level of controller’s nesting is expected"
I think I (we?) need a bit more information on that part here.
However, the warning on async still stands :)
E.g. if two backend calls within the controllers are
independent they must be performed in parallel.
If they are truly independent you might be able to use asynch JavaScript calls from the client and achieve some degree of parallelism that way.