I'm looking for a pattern to implement in my application that would allow me to cleanly have my application pull information from several http requests, where each request needs to run sequentially, one after the other, and feed information from the former request to the next request. I have worked through many of the solutions in this question, but many of the answers are for old versions of Swift, there are conflicting solutions, there are non-working solutions, and none address getting data from one request to the next request. Also many of the ideas don't extend to more than about two requests.
The reason for having several requests that do not overlap is that data from earlier requests feed into the next request. Or it could be that depending on the data, it might make sense to skip some http requests.
I have tried nesting requests, which works for one level deep, but does not work two or more levels deep. It also is hostile to logic where skipping some requests is required.
Alamofire.request(...).responseString { formResponse in
Alamofire.request(...).responseString { submitResponse in
Alamofire.request(...).responseString { getDataResponse in
// not only is this messy, it also did not proven to wait until all previous threads were done before working on the nested item.
}
}
}
I have also tried to set up a serial queue with the Alamofire-Synchronous package imported:
let serialQ = DispatchQueue(label: "serialQ")
var info1 = ""
var info2 = ""
var info3 = ""
serialQ.async {
Alamofire.request(...).responseString { formResponse in
....
info1 = "good stuff"
}
}
serialQ.async {
Alamofire.request(...).responseString { submitResponse in
....
if info1 == "x" {...}
info2 = "more good stuff"
}
}
serialQ.async {
Alamofire.request(...).responseString { getDataResponse in
....
if info2 == "x" {...}
info3 = "even more good stuff"
}
}
The above code acts as if that synchronous functionality of the package isn't doing anything to prevent Alamofire from spawning concurrent threads. In other words, it just cranks up all of the requests, one after the other. This might work, I didn't see where my code actually used the code in the package.
I also tried to use the idea presented in this SO answer, but I could not get it working. In fact I worked through all of the answers in that question, and none proved to work for me or some of the "chaining" solutions did not answer the question of how you feed data from one request to the next.
I must me making this harder than it has to be!
Making an http request, waiting for the result, and using it in the next http request, (and the next, and the next) has got to have an elegant swift / Alamofire programming pattern.
A good answer to this question would allow the reader to be able to construct code with the modern/current versions of Swift and Alamofire, that would to chain several http calls where the response from the former request is used in the next request. I've used 3 dependent requests in my examples, but should extend to "n" without getting bogged down.
Related
I have a system that processes images. Essentially, I provide an ID to it, and it fetches a source image, and then it begins performing transformations on it to resize and reformat it.
This system gets quite a bit of usage, and one of the things that I've noticed is that I tend to get many requests for the same ID simultaneously, but in different requests to the webserver.
What I'd like to do is "batch" these requests. For example, if there's 5 simultaneous requests for the image "user-upload.png", I'd like there to be only one HTTP request to fetch the source image.
I'm using NestJS with default scopes for my service, so the service is shared between requests. Requests to fetch the image are done with the HttpModule, which is using axios internally.
I only care about simultaneous requests. Once the request finishes, it will be cached, and that prevents new requests from hitting the HTTP url.
I've thought about doing something like this (Pseudocode):
#Provider()
class ImageFetcher {
// Store in flight requests as a map between id:promise
inFlightRequests = { }
fetchImage(id: string) {
if (this.inFlightRequests[id]) {
return this.inFlightRequests[id]
}
this.inFlightRequests[id] = new Promise(async (resolve, reject) => {
const { data } = await this.httpService.get('/images' + id)
// error handling omitted here
resolve(data)
delete inFlightRequests[id]
})
return this.inFlightRequests[id]
}
}
The most obvious issue I see is the potential for a memory leak. This is solveable with more custom code, but I thought I'd see if anyone has any suggestions for doing this without writing more code.
In particular, I've also thought about using an axios interceptor, but I'm not entirely sure how to handle that properly. Any pointers here would be really appreciated.
I am designing a call manager with the help of RXSwift (ReactiveX) that continuously interacts with an API. The call manager comprises several objects that itself comprises an indicator (indicating status information loaded from the API) and control (requests to be sent to the API).
class CallManagerObjectA() {
var control = PublishSubject<String>()
var indicator = BehaviorSubject<String>(value: "string status")
}
Within the call manager, a scheduler regularly provides new values to the indicator observable:
<... API response ...>
indicator.onNext(newValue)
Somewhere else in a view controller, the indicator will be observed for a label:
indicator.subscribe(onNext: { label.stringValue = $0 })
Within the same view controller, the user can control the object status via GUI elements continuously:
control.onNext(commandValue)
Within the call manager, the control will be observed for an API call:
control.subscribe(onNext: { (command) in
// API request call
})
So far so good, this is working very well with reactive patterns.
Now, I am looking for a good solution to handle errors, if the call manager recognizes errors during the API interaction and show these errors to the user in the view controller. I was immediately thinking of something like this:
// Call manager recognizes the error
control.onError(error)
...
// Call manager ignores errors for the subscriber
control.retry().ignoreErrors().subscribe(onNext: { (command) in
// API request call
})
...
// View controller shows the errors
indicator.subscribe(onNext: { label.stringValue = $0 })
control.subscribe(onError: { print("error", $0) })
This however ends up in an infinite loop.
I fear that I have a fundamental understanding issue with reactive programming, or I miss something very important, but I am not able to understand how the handle errors in this reactive pattern environment.
Based on the code you have shown, you have a big misunderstanding, not just with how to handle Errors, but with how to program reactively in general. Try watching this video "Reactive Programming: Why It Matters"
To answer your specific question, there are two misunderstandings here:
When you call control.onError(_:) it will be the last call you will be able to make on control. Once it emits an error it will stop working.
The retry() operator asks its source to "try again on Error". If it's source is determinate, then it will just do the exact same thing it did before and emit the exact same output (i.e., the same error it emitted last time.) In the case of a PublishSubject, it doesn't know why onError was called. So the best it can do is just emit the error again.
Honestly, I consider this a bug in the API because subscribing to a publish subject that emitted an error at some point in the past should just do nothing. But then, you wouldn't be asking why you got an infinite loop. Instead you would be asking why your control stopped emitting events.
I am struggling to come with proper REST URL for converting one resource into another. The API method does not do any CRUD operations but instead transform/convert one resource into another type of resource.
I have 2 resources Workunit and Document. I have 3 operations on these two resources
1> trasform Workunit into Document
2> sync Workunit into Document (different logic than transform)
3> transform Document into Workunit
and i have the following urls
[POST] api/v1/workunits/transform
[POST] api/v1/workunits/sync
[POST] api/v1/documents/transform
problem here is action is a part of REST URL
any suggestions?
problem here is action is a part of REST URL
That's not a problem - clients don't depend on the URL for semantics, so you can use any spelling you like; api/v1/4dc233fa-c77c-49d7-b7d6-296ffeb89612 is perfectly satisfactory.
It's analogous to having a verb as a variable name -- it may not be in keeping with your local coding standards, but the compiler doesn't care. So too is it with your URL and the general purpose components that use it.
Choosing a good identifier is like choosing a good name; it requires having a clear understanding of what the thing is. In the case of URI/URL, the thing being identified is a resource, which is to say something that is described by a document. GET/POST/PUT/DELETE and so on are all requests that we do something interesting with the underlying document.
So the usual pattern might be to POST a transform message to the workunit resource, or to POST a transform message to the Document resource, or to POST a sync message to the workunit resource.
Hmm, that last one sounds backwards; if the workunit is unchanged, and the Document is changed by the sync, then you would probably send a sync message to the Document resource.
So if I have /api/v1/documents/1, and I need to sync it, then I would normally use POST /api/v1/documents/1, with the sync semantics described in the message body (on the web, that would usually be an application/x-www-form-urlencoded representation of the sync message).
But it could just as easily be a message that says "Sync documents/1 with workitem/2" that I POST to the todo list for the synchronizer.
We are just putting documents politely into the server's in-tray, so that it can do useful work. The in-tray can have whatever label you want.
It is fine with given situation.
Nevertheless, if I am getting you right it may be a good idea to create two different controllers.
It's up to you but think of changing structure a little bit:
Separate the logic of Transformation and Sync into two different controllers, so you can avoid URL issue.
TransformationController
[Route("api/v1/transformation-controller/")]
TransformationController : ControllerBase
{
[HttpPost("workunits")]
public Task<Response> TransformWorkunits()
{
//logic
}
[HttpPost("documents")]
public Task<Response> TransformDocuments()
{
//logic
}
}
SynchronizationController
[Route("api/v1/synchronization-controller/")]
TransformationController : ControllerBase
{
[HttpPost("workunits")]
public Task<Response> SyncWorkunits()
{
//logic
}
}
So the URLs will be:
[POST] api/v1/transformation-controller/workunits
[POST] api/v1/synchronization-controller/workunits
[POST] api/v1/transformation-controller/documents
So this is a way to avoid verbs and fit REST rules.
If there will be more objects to transform/sync from and into, then you'll have to improve this approach.
I am building a bot for for Facebook Messenger using Microsoft Bot Framework. I am planning to use CosmosDB for State Management and also as my backend data store. (I am not stuck to CosmosBD and can use any other store if needed)
I need to send daily/weekly proactive messages(push notifications) to users based on their time preference. I will capturing their time preference when they first interact with the bot.
What is the best way to deliver these notifications?
As I will be storing these preferences in CosmosDB, I am thinking using ComosDB trigger of creating an Azure Function and schedule it based on the user time preference. This Azure function will make a call to my webhook which will deliver these messages. If requried, I will change Function schedule when a user changes his/her preference.
My questions are:
Is this a good approach?
Are there any other alternatives (Notifications Hub?)
I should be able to set specific times for notifications (like at the top of the hour or something like that), does it make sense to schedule an Azure Function to run at these hours rather than creating a function based on user preference (I can actually combine these two approaches too)
Thank you in advance.
First, I don't think there's any "right" answer to be given here; it's going to depend a lot on your domain's specific needs. Scale is going to play a major factor in the design of this. Will you have 100 users? 10000 users? 1mil users? I'm going to assume you want to design for maximum scale up front, but it could be overkill.
First, based on what you've described, I don't think a CosmosDB trigger is necessarily the solution to your problem because that's only going to fire when the preference data is created/updated. I assume that, from that point forward, your function needs to continuously fire at the time slot they've opted into, correct?
So let's pretend you let people choose from the 24hrs in the day. A naïve approach would be to simply use a scheduled trigger that fires up every hour, queries the CosmosDB for all the documents where the preference is set to that particular hour and then begins sending out notifications from there. The problem is how you scale from there and deal with issues of idempotency in the face of failures.
First off, a timer trigger only ever spins up one instance. If you were to just go query the CosmosDB documents and start processing them one by one in the scope of that single trigger, you'd hit a ceiling relatively quickly on how many notifications you can scale to. Instead what you'd want to do is use that timer trigger to fan out the notifications to as many "worker" function instances as possible. The timer trigger can act as the orchestrator in the sense that it can own the query against the CosmosDB and then turn each document result it finds for that particular notification time window into a message that it places on a queue to be processed by a separate function which will scale out on its own.
There are actually a couple ways you can accomplish this with Azure Functions, it really depends on how early an adopter of technology you are comfortable with being.
The first is what I would call the "manual" way which would be done by simply using the existing Azure Storage Queue extension by taking an IAsyncCollector<YourNotificationWorkerMessage> as a parameter to the timer function that's bound to the worker queue and then pumping out the messages through that. Then you write a second companion function which uses a QueueTrigger, bind it to that same queue, and it will take care of processing each message. This second function is where you get the scaling, enabling process all of the queued messages as quickly as possible based on whatever scaling parameters you choose to configure. This is the "simplest" approach
The second approach would be to adopt the newer Durable Functions extension. With that model, you don't have to directly think about creating a worker queue. You simply kick off a new instance of your orchestrator function from the timer function and the orchestrator fans out the work by invoking N "concurrent" calls to an action for each notification. Now, it happens to distribute those calls using queues under the covers, but that's an implementation detail that you need no longer maintain yourself. Additionally, if the work of delivering the notification requires more involved work and/or retry logic, you might actually consider using a sub-orchestration instead of a simple action. Finally, another added benefit of this approach, is that you can "fan back in" to your main orchestrator function once all the notifications are delivered to do some follow up work... even if that's simply some kind of event logging that the notification cycle has completed for this hour.
Now, the challenge with either of these approach is actually dealing with failure in initially fetching the candidates for notification from CosmosDB, paging through the results and making sure you actually fan all of them out in an idempotent manner. You need to deal with possible hiccups as you page and you need to deal with the fact that your whole function could be torn down and you might have to restart. Perhaps on the initial run of the 8AM notifications you got through page 273 out of 371 pages and then you got hit with a complete network connectivity fail or the VM your function was running on suffered a power failure. You could resume, but you'd need to know that you left off on page 273 and that you actually processed the 27th record out of that page and start from there. Otherwise, you risk sending double notifications to your users. Maybe that's something you can accept, maybe it's not. Maybe you're ok with the 27 notifications on that page being duplicated as long as the first 272 pages aren't. Again, this is something you need to decide for your domain, but if you want to avoid this issue your orchestrator function will need to track its progress to ensure that it doesn't send out dupes. Again I would say Durable Functions has a leg up here as it comes with the ability to configure retries. Maintaining the state of a particular run is left up to the author in either approach though.
I use pro-active dialog extensively with botframwork and messenger without any issue. During your facebook approval process you simply need to inform them you will be sending notifications trough messenger with your bot. Usually if you use it to inform your user and stay away from promotional content you should be fine.
I also use azure function to trigger the pro-active dialog from a custom controller endpoint.
Bellow sample code for azure function:
public static void Run(TimerInfo notificationTrigger, TraceWriter log)
{
try
{
//Serialize request object
string timerInfo = JsonConvert.SerializeObject(notificationTrigger);
//Create a request for bot service with security token
HttpRequestMessage hrm = new HttpRequestMessage()
{
Method = HttpMethod.Post,
RequestUri = new Uri(NotificationEndPointUrl),
Content = new StringContent(timerInfo, Encoding.UTF8, "application/json")
};
hrm.Headers.Add("Authorization", NotificationApiKey);
log.Info(JsonConvert.SerializeObject(hrm));
//Call service
using (var client = new HttpClient())
{
Task task = client.SendAsync(hrm).ContinueWith((taskResponse) =>
{
HttpResponseMessage result = taskResponse.Result;
var jsonString = result.Content.ReadAsStringAsync();
jsonString.Wait();
if (result.StatusCode != System.Net.HttpStatusCode.OK)
{
//Throw what ever problem as an exception with details
throw new Exception($"AzureFunction - ERRROR - HTTP {result.StatusCode}");
}
});
task.Wait();
}
}
catch (Exception ex)
{
//TODO log
}
}
Bellow sample code for starting the pro-active dialog:
public static async Task Resume<T, R>(string resumptionCookie) where T : IDialog<R>, new()
{
//Deserialize reference to conversation
ConversationReference conversationReference = JsonConvert.DeserializeObject<ConversationReference>(resumptionCookie);
//Generate message from bot to user
var message = conversationReference.GetPostToBotMessage();
var builder = new ContainerBuilder();
using (var scope = DialogModule.BeginLifetimeScope(Conversation.Container, message))
{
//From a cold start the service is not yet authenticated with dev bot azure services
//We thus must trust endpoint url.
if (!MicrosoftAppCredentials.IsTrustedServiceUrl(message.ServiceUrl))
{
MicrosoftAppCredentials.TrustServiceUrl(message.ServiceUrl, DateTime.MaxValue);
}
var botData = scope.Resolve<IBotData>();
await botData.LoadAsync(CancellationToken.None);
//This is our dialog stack
var task = scope.Resolve<IDialogTask>();
T dialog = scope.Resolve<T>(); //Resolve the dialog using autofac
try
{
task.Call(dialog.Void<R, IMessageActivity>(), null);
await task.PollAsync(CancellationToken.None);
}
catch (Exception ex)
{
//TODO log
}
finally
{
//flush dialog stack
await botData.FlushAsync(CancellationToken.None);
}
}
}
Your dialog needs to be registered in autofac.
Your resumptionCookie needs to be saved in your db.
You might want to check FB policy regarding proactive messages
There’s a 24h limit but it might not be totally screwed in your case
https://developers.facebook.com/docs/messenger-platform/policy/policy-overview#standard_messaging
The preamble
We're implementing a MVC2 site that needs to consume an external API via https (We cannot use WCF or even old-style SOAP WebServices, I'm afraid). We're using AsyncController wherever we need to communicate with the API, and everything is running fine so far.
Some scenarios have come up where we need to make multiple API calls in series, using results from one step to perform the next.
The general pattern (simplified for demonstration purposes) so far is as follows:
public class WhateverController : AsyncController
{
public void DoStuffAsync(DoStuffModel data)
{
AsyncManager.OutstandingOperations.Increment();
var apiUri = API.getCorrectServiceUri();
var req = new WebClient();
req.DownloadStringCompleted += (sender, e) =>
{
AsyncManager.Parameters["result"] = e.Result;
AsyncManager.OutstandingOperations.Decrement();
};
req.DownloadStringAsync(apiUri);
}
public ActionResult DoStuffCompleted(string result)
{
return View(result);
}
}
We have several Actions that need to perform API calls in parallel working just fine already; we just perform multiple requests, and ensure that we increment AsyncManager.OutstandingOperations correctly.
The scenario
To perform multiple API service requests in series, we presently are calling the next step within the event handler for the first request's DownloadStringCompleted. eg,
req.DownloadStringCompleted += (sender, e) =>
{
AsyncManager.Parameters["step1"] = e.Result;
OtherActionAsync(e.Result);
AsyncManager.OutstandingOperations.Decrement();
}
where OtherActionAsync is another action defined in this same controller following the same pattern as defined above.
The question
Can calling other async actions from within the event handler cause a possible race when accessing values within AsyncManager?
I tried looking around MSDN but all of the commentary about AsyncManager.Sync() was regarding the BeginMethod/EndMethod pattern with IAsyncCallback. In that scenario, the documentation warns about potential race conditions.
We don't need to actually call another action within the controller, if that is off-putting to you. The code to build another WebClient and call .DownloadStringAsync() on that could just as easily be placed within the event handler of the first request. I have just shown it like that here to make it slightly easier to read.
Hopefully that makes sense! If not, please leave a comment and I'll attempt to clarify anything you like.
Thanks!
It turns out the answer is "No".
(for future reference incase anyone comes across this question via a search)