Precaching network responses using `Isolates` with Dio and Hive - flutter

I just want to precache some endpoint calls at the beginning of the app to load faster some request since the backend service is really slow.
I've tried using Isolates for this but seems like Hive Cache doesn't support that, so even if I try to request on another Isolate it will ended up taking the same time (20-30 seconds) the same request when I'm trying to pull for the second time, where it should cache it.
Since I read it wasn't supported yet, and I personally think is critical, I moved to just call the endpoints meanwhile the app is loading a bunch of stuff in the main thread. I dont want to delay any more the app so I just want to preload 5 endpoints, so that the next time I'm requesting again it can perform faster.
1. First Approach, with Isolates
I'm calling this inside a function
final requestsToPrecache = events
.map((entityId) =>
_dataRepository.getEventTable(entityId: entityId))
.toList();
compute(precacheFutureOperations, requestsToPrecache);
Then this function is the one I'm passing thru Isolates
void precacheFutureOperations(List<Future> functions) {
Future.wait(functions);
}
2. Second Approach, just not calling await on the Network Request to trigger the request and cache them, so I dont need to wait for the response since I just want to execute it and keep it in cache before it is used, so I just call b
precacheFutureOperations(requestsToPrecache);
All of this trigger the endpoints I want to precache succesfully, I am monitoring that using proxyman. The weird part is that it doesnt cache them this way. Only after I call the request normally for the Detail Screen, is that it actually caches as expected if I tried to re-enter the screen.
What can I do to precache multiple request at the beginning of the app

Related

Which service worker event indicates it has controlled the page, and will intercept web traffic?

In my web app, some web requests must be intercepted and modified by the service worker, otherwise the requests will fail. This is especially important on the very first visit for a new user. I use clientsClaim() to ensure that.
Since I need to make sure the service worker is ready before I make the request, I tried to wait for navigator.serviceWorker.ready:
await navigator.serviceWorker.ready;
fetch(myRequest);
However, I found it doesn't work as intended. The very first request on the first visit is not intercepted. So I tried to add some wait time:
await navigator.serviceWorker.ready;
await twoSeconds();
fetch(myRequest);
This works, but it damages user experience because it delays the first meaningful UI. On the other hand, I also can't be sure 2 seconds is long enough for every computer.
What's the event that can tell me as soon as the the sw is ready to intercept traffic? It's only a problem on the first visit, but ideally the event will fire on every reload, because the code is easier to write if I simply await the same thing on every visit.
I think you're looking for a promise that you can use to signal when the current page is under control of a service worker.
This can be achieved via
await new Promise(r => {
if (navigator.serviceWorker.controller) return r();
navigator.serviceWorker.addEventListener('controllerchange', e => r());
});
// At this point, the page will be controlled by a service worker.
This code is adapted from this GitHub discussion, and there's more context there.
Generally speaking, it's not great to design a page that will only work if it's controlled by a service worker, since service workers are intended to be progressive enhancement, rather than a core requirement. But if you have that use case, the code above will help.

Delaying HTTP request phases using FiddlerCore

I am using FiddlerCore to test out my applications behavior when waiting a long time for server response. I am using c++ winhttp.h library in my app. I am trying to introduce delay before triggering each async callback.
So far I have tried two solutions:
Adding oSession["response-trickle-delay"] = receiveDelayinMillisecPerKb; as explained in this blog post, and this simulates slow streaming from storage detectable when WinHttpReadData is called.
Adding Thread.Sleep(delayMs) in different fiddler session state handlers (BeforeRequest, RequestHeadersAvailable, BeforeResponse, ResponseHeadersAvailable) but from my app it seems that all of them prolong the time between WinHttpSendRequest method and WINHTTP_CALLBACK_STATUS_SENDREQUEST_COMPLETE status callback.
Is there any other way to introduce delay in request in different request states using Fiddlercore?

Alamofire global queue with pause between requests

I'm working with an API which only permits a maximum of 5 requests per second. If this limit is exceeded the API returns a 429 server error.
My intuition says that to handle this, I should put all requests into some form of serial queue, and enforce a delay of 0.21s between requests, but I'm not quite sure how to accomplish this. I'm also not sure if using a serial queue is a good idea, as then I'll lose the ability to have multiple requests running at the same time.
I am using adapter and retrier objects to handle refreshing my OAuth session token, so I guess this may be a good place to put my logic.
Has anyone done something like this before, or have any ideas?
Actually I'd probably go a different direction, rather than trying to throttle all requests, I'd look at the response from each request and if it's a 429, I'd re-queue the request via an async closure with a 1 second time delay.
This means that as long as requests are coming in slowly they are executed immediately. But when you try the 6th request, it's shifted into the next second.
The only problem you're going to have to consider (regardless of solution) is what happens if requests keep coming in faster than the API will allow. ie. what happens if you get 6, or 7 or 100 requests per second, for every second? How are you going to deal with the extra requests that will never get executed.
At some point your code is going to have to start failing requests. Alternatively you need to push the server people to run up more servers or give you more bandwidth.

Can I use async controllers in the following scenario?

I have an application in Asp.net MVC where at some point I would like to display a modal dialog to the user that would display process execution progress indicator.
The process behind the scenes does a lot of database data processing (based on existing data it generates lots of resulting records that get written back to database as well). Process may take anything from a brief moment to a very long time (depending on existing data).
Application will initiate this process asynchronously (via Ajax request) and display progress in the same manner.
The problem
I've read a bit about Async controllers where one can asynchronously start a process and will informed about the end of it but there's no progress indication and I'm not really sure how browser timeouts are handled. As far as the client goes an async request is the same as synchronous one. Client will therefore wait for response (as I understand it). the main difference being that server will execute something in async manner so it won't block other incoming requests. What I should actually do is:
make a request that would start the process and respond to the client taht process has started.
client would them periodically poll the server for process progress status getting immediate response back with percentage value (probably as JSON)
when progress would be 100% it would mean that it ended so client would know to make a request for results.
I'm not convinced that async controllers work this way...
The thing is that I'm not really sure I understand async controllers hence am not sure which approach should I use approach this problem as just described? I see two possibilities myself:
Asp.net MVC Async controllers if they can work this way
Windows Service app that processes data on request and reports its progress - this service would be started by writing a particular record to DB using a normal controller action; that would start it and then service would be writing its progress status to DB so my Asp.net MVC app would be able to read it on client process polling requests.
I haven't used Asynch controllers myself in a project. However here's a link to someone who has.
asynchronous-processing-in-asp-net-mvc-with-ajax-progress-bar
I have personally used Number 2 in a large production project.
Number 2 was a Service App running on a separate server using OpenSSH to communicate between the two servers. We'd poll for progress periodically to update the progress bar to the clients UI via AJAX.
Additionally by separating your web server from your long running process you are separating your concerns. You web server is not interested in writing files to disk, handling IO, etc and so shouldn't be burdended with such.
If your long running process has to be killed or fails then this wont affect your web server handling requests, and processing transactions.
Another suggestion would be for an extremely long running process is not to burden the client with waiting, give them an option to come back later to see the progress. I.e. send them an e-mail when its done.
Or actually show them something interesting, in our case we had a signed Java Applet show exactly what their process is doing at that exact moment.

Can I use a continuous background thread to update the iPhone UI without using NSTimer?

Let's say that if I read from www.example.com/number, I get a random number. In my iPhone app, I want to be able to continuously read from that address and display the new number on the screen after each request is finished. Let's also assume that I want this process to start as soon as the view loads. Lastly, as a side-note, I'm using ASIHTTPRequest to simplify the web requests.
Approach 1: In my viewDidLoad method I could synchronously read from the URL in a loop (execution will not continue until I get a response from the HTTP request). Pros: the requests are serial and I have full control to respond to each one. Cons: the UI never gets updated because I never exit the function and give control back to the run time loop. Clearly, this is not a good solution.
Approach 2: In my viewDidLoad method I create a timer which calls a fetchURL function once per second. Pros: each request is in a separate thread, and the UI updates after each request is finished. Cons: the requests are in separate threads, and cannot be controlled well. For example, if there is a connection timeout on the first request, I want to be able to display an error popup, and not have any further requests happen until settings are changed. However, with this approach, if it takes 3 seconds to timeout, two additional requests will have already been started in that time. If I just slow down the timer, then data comes in too slowly when the connection is working well.
It seems like there should be some approach which would merge the benefits of the first two approaches I mentioned. I would like a way that I could decide whether on not to send the next request based on the result of the previous request.
Approach 3: I considered using a timer which fires more quickly (say every .25 seconds), but have the timer's function check a flag to see what to do next. So, if the previous request has finished, it sends a new request (unless there was an error). Otherwise, if the previous request has not finished, the timer's function returns without sending a new request. By firing this timer more quickly, you would get better response time, but the flag would let me get the synchronization I wanted.
It seems like Approach 3 would do what I want, but it also seems a little forced. Does anyone have a suggestion for a better approach to this, or is something like Approach 3 the best way to do it?
You could do this using GCD with less code and using fewer resources. This is how you could do it:
In viewDidLoad call a block asynchronously (using dispatch_async) that does the following:
Load the data with a synchronous call and handle timeouts if it failed.
If successful, inform the main thread to update the UI.
Queue a new block to run after a delay that does the same thing (using dispatch_after).
To call back to the main thread from another thread I can think of these methods:
If you want to update a custom view, you can set setNeedsDisplay from your block
Otherwise, you could queue a block on what's called "main queue", which is a queue running on the main thread. You get this queue by calling dispatch_get_main_queue. and then treat it like any other queue (for example you can add your block by calling dispatch_async).
If you don't want to use blocks you can use the NSObject's performSelectorOnMainThread:withObject:waitUntilDone: method.
See GCD Reference for more details.
That said, you should never keep performing small requests so frequently (unless for specific tasks like fetching game data or something). It will severely reduce battery life by keeping antenna from sleeping.
I believe an NSOperation is what you need. Use the number 1 solution above, but place the code in your NSOperation's main method. Something like this:
The .h file
#interface MyRandomNumberFetcher : NSOperation {
}
#end
The .m file
#implementation MyRandomNumberFetcher
- (void) main {
// This is where you start the web service calls.
}
#end
I'd also recommend adding a reference to the UI controller so your operation queue class can call it back when it's appropriate.
Here's another suggestion. Create an NSOperationQueue that will run your requests on a different thread. If you find you need to refresh the UI call performSelectorOnMainThread. When the request completes create another request and add it to the queue. Set the queue to run only one action at a time.
This way you'll never have two requests running at the same time.