How To Return Aggregated Result of Last Actor? - akka.net

I have setup ActorSystem to perform MapReduce on a collection of data. I have now got last Actor to collate all results. How can i channel the result back to the "service" which initated this Actor System ?
//in below call i wire up all Actors
var getActorSystem = CreateActorSystem();
//I wait for ActorSystem to complete
getActorSystem.WhenTerminated.Wait();
How do i get the result from last Actor in ActorSystem which now has the final result ?

You will need to use the Ask functionality in Akka.NET. Ask will return a Task and thus you will need to wait for its completion after which you can get access to the response from Task.Result.
The docs cover this scenario http://getakka.net/docs/working-with-actors/sending-messages#ask-send-and-receive-future.

Related

How to push Salesforce Order to an external REST API?

I have experience in Salesforce administration, but not in Salesforce development.
My task is to push a Order in Salesforce to an external REST API, if the order is in the custom status "Processing" and the Order Start Date (EffectiveDate) is in 10 days.
The order will be than processed in the down-stream system.
If the order was successfully pushed to the REST API the status should be changed to "Activated".
Can anybody give me some example code to get started?
There's very cool guide for picking right mechanism, I've been studying from this PDF for one of SF certifications: https://developer.salesforce.com/docs/atlas.en-us.integration_patterns_and_practices.meta/integration_patterns_and_practices/integ_pat_intro_overview.htm
A lot depends on whether the endpoint is accessible from Salesforce (if it isn't - you might have to pull data instead of pushing), what authentication it needs.
For push out of Salesforce you could use
Outbound Message - it'd be an XML document sent when (time-based in your case?) workflow fires, not REST but it's just clicks, no code. The downside is that it's just 1 object in message. So you can send Order header but no line items.
External Service would be code-free and you could build a flow with it.
You could always push data with Apex code (something like this). We'd split the solution into 2 bits.
The part that gets actual work done: At high level you'd write function that takes list of Order ids as parameter, queries them, calls req.setBody(JSON.serialize([SELECT Id, OrderNumber FROM Order WHERE Id IN :ids]));... If the API needs some special authentication - you'd look into "Named Credentials". Hard to say what you'll need without knowing more about your target.
And the part that would call this Apex when the time comes. Could be more code (a nightly scheduled job that makes these callouts 1 minute after midnight?) https://salesforce.stackexchange.com/questions/226403/how-to-schedule-an-apex-batch-with-callout
Could be a flow / process builder (again, you probably want time-based flows) that calls this piece of Apex. The "worker" code would have to "implement interface" (a fancy way of saying that the code promises there will be function "suchAndSuchName" that takes "suchAndSuch" parameters). Check Process.Plugin out.
For pulling data... well, target application could login to SF (SOAP, REST) and query the table of orders once a day. Lots of integration tools have Salesforce plugins, do you already use Azure Data Factory? Informatica? BizTalk? Mulesoft?
There's also something called "long polling" where client app subscribes to notifications and SF pushes info to them. You might have heard about CometD? In SF-speak read up about Platform Events, Streaming API, Change Data Capture (although that last one fires on change and sends only the changed fields, not great for pushing a complete order + line items). You can send platform events from flows too.
So... don't dive straight to coding the solution. Plan a bit, the maintenance will be easier. This is untested, written in Notepad, I don't have org with orders handy... But in theory you should be able to schedule it to run at 1 AM for example. Or from dev console you can trigger it with Database.executeBatch(new OrderSyncBatch(), 1);
public class OrderSyncBatch implements Database.Batchable, Database.AllowsCallouts {
public Database.QueryLocator start(Database.BatchableContext bc) {
Date cutoff = System.today().addDays(10);
return Database.getQueryLocator([SELECT Id, Name, Account.Name, GrandTotalAmount, OrderNumber, OrderReferenceNumber,
(SELECT Id, UnitPrice, Quantity, OrderId FROM OrderItems)
FROM Order
WHERE Status = 'Processing' AND EffectiveDate = :cutoff]);
}
public void execute(Database.BatchableContext bc, List<sObject> scope) {
Http h = new Http();
List<Order> toUpdate = new List<Order>();
// Assuming you want 1 order at a time, not a list of orders?
for (Order o : (List<Order>)scope) {
HttpRequest req = new HttpRequest();
HttpResponse res;
req.setEndpoint('https://example.com'); // your API endpoint here, or maybe something that starts with "callout:" if you'd be using Named Credentials
req.setMethod('POST');
req.setHeader('Content-Type', 'application/json');
req.setBody(JSON.serializePretty(o));
res = h.send(req);
if (res.getStatusCode() == 200) {
o.Status = 'Activated';
toUpdate.add(o);
}
else {
// Error handling? Maybe just debug it, maybe make a Task for the user or look into
// Database.RaisesPlatformEvents
System.debug(res);
}
}
update toUpdate;
}
public void finish(Database.BatchableContext bc) {}
public void execute(SchedulableContext sc){
Database.executeBatch(new OrderSyncBatch(), Limits.getLimitCallouts()); // there's limit of 10 callouts per single transaction
// and by default batches process 200 records at a time so we want smaller chunks
// https://developer.salesforce.com/docs/atlas.en-us.apexref.meta/apexref/apex_methods_system_limits.htm
// You might want to tweak the parameter even down to 1 order at a time if processing takes a while at the other end.
}
}

Using VRS for concurrent request

We need to use a single instace of VRS to support concurrent request.
We have a requirement where multiple different users should be able to create a route plan for different vehicles and locations same time. However, looking at VRS functionality, I am not able to understand how applications supports it. For demo, when I create a different route using different browser, it always merges first and second request and give one single result.
Just a little more elobration on the question:
We are aiming to convert requests as REST API endpoints which will be invoked by different uses same time for their usecase.
Eg. Request 1: Vehicle 1&2 with 50 locations. VRS can calculate route & give one message with all detailed calculations for request1.
Request 2: Vehicle 3 & 4 with 40 locations. So VRS can calculate route which later we can get as one message with all detailed calculations limited to request 2.
Both requests can be submitted same time & application should considered as separate requests without getting merged.
Is there a way to add request ID or any other paramaters to achive this?
For multi-tenant solving, the SolverManager API is ideal:
public class TimeTableService {
// tenantId is Long, but it can also be String or UUID
private SolverManager<TimeTable, Long> solverManager;
// Returns immediately, call it for every dataset
public void solveBatch(Long tenantId) {
solverManager.solve(tenantId,
// Called once, when solving starts
this::findById,
// Called once, when solving ends
this::save);
}
public TimeTable findById(Long tenantId) {...}
public void save(TimeTable timeTable) {...}
}

Future/Promise like stuff for Trio in Python?

Say I have a class Messenger which is responsible for sending and receiving messages. Now I have a service that sends out requests and waits for responses via it, matching each pair with an id field in the message. In asyncio I would do:
class Service:
...
async def request(self, req):
new_id = self._gen_id()
req.id = new_id
fu = asyncio.Future()
self._requests[new_id] = fu
await self._messenger.send(req)
return await fu
def handle_response(self, res):
try:
fu = self._requests.pop(res.req_id)
except KeyError:
return
fu.set_result(res)
So I could send out multiple requests from different tasks, and in each task wait for the corresponding response. (And some messages may not have a corresponding response that are handled in another way.)
But how do I do this in Trio? Should I create an Event / Condition / Queue for each request and put the response in a predefined place?
If yes, which is the best for this scenario? Or there is another way to do this?
You could create a simple class that contains an Event and your result.
However, strictly speaking events are overkill because multiple tasks can wait on an event, which you don't need, so you should use trio.hazmat.wait_task_rescheduled. That also gives you a hook you can use to do something when the requesting task gets cancelled before receiving its reply.
http://trio.readthedocs.io/en/latest/reference-hazmat.html#low-level-blocking

How to cancel a deferred NServiceBus Message?

Say I use the deferred messaging feature to send a message at some later future point in time, but then later I might want to cancel that message.
Question 1 - When making the original bus.Defer(...) call, how do I get a unique identifier back for that message? I would expect there to be a message id or a timeout id of some sort.
Question 2 - Short of calling the RavenDB database directly, is there a way to query the bus to get back all pending deferred messages?
Question 3 - Is there some way to cancel a deferred message? I would expect something like bus.CancelDeferred(messageid)
Is any of this available, or are there any other mechanisms I can use to achieve similar results?
I've had the need to abandon deferred messages and outstanding replies a few times, and I did it by "incrementing the correlation ID" on my saga. You don't mention sagas though, so I'm not sure if this solution will be usable to you. I do think, however, that it goes under "any other mechanisms" that you ask for :)
Check out this example - here I have the state of my saga which, among other things, contains a custom CorrelationId:
public class MySagaData : ISagaData
{
// ... the usual stuff here
public string CorrelationId { get; set; }
}
and then, each time I defer a message or request something, I correlate the deferred message and/or reply with the current value of the correlation ID:
bus.Defer(time, new Something { CorrelationId = Data.CorrelationId });
bus.Send(new SomeRequest { CorrelationId = Data.CorrelationId });
thus conceptually correlating the deferred message and the reply with the current state of the saga.
And then, in cases where I want to abandon all outstanding messages, I simply re-set the saga's correlation ID to a new value - I usually set the value to something like somethingWithBusinessMeaning/timestamp.
This way, abandoned messages will not correlate with any saga instance, effectively being ignored.
Does it make sense?
1) There is currently no way to do this. You could add your own header with a app specific id if you need to keep track of them
2) No, you have to query the storage as you mention. That said what would be the use case for this?
3) No, and this is by design. Given that you can't assume when a message will arrive you can't rely on timeouts being canceled since a defered message might be stuck in a queue and processed right after you cancel. The "cancel" message might also get lost.
In short: your code needs to be prepared to discard "invalid" messages no matter what.

Problem with WCF Response - getting multiple responses

I am using Silverlight, WCF combination.
Currently, I am facing one problem with service response.
I am using request response service type.
I have 100 Items and i am going to call 100 services to fetch it's properties.
foreach (ItemDto item in items)
{
ServiceCall();
ServiceSendCount++;
}
private void OnServiceCallCompleted(.....)
{
ServiceReceiveCount++;
}
If i am sending 5 service calls then it returns with 5*5 = 25 responses.
same with as i am sending 10 service calls then it returns with 10*10 = 100 responses.
I am not able to figure out what was the problem....
Can anyone please shed some light on this?
Update:
Please find herewith the service call method.
I agree that each and every time i am sending OnServiceCallCompleted ..
foreach (ItemDto item in items)
{
itemPropertyService.GetItemProperties([parameters] , OnServiceCallCompleted);
ServiceSendCount++;
}
private void OnServiceCallCompleted(.....)
{
ServiceReceiveCount++;
/* here contains my logic to process the response
If it cames mulriple time then my logic will down
*/
}
Can you please let me know the solution for same. As the change in the service is not possible right now.
But it will create the problem of response time.
Suppose i am going to send the request for 100 items at a time.
In My first approch, i will get the first 100 responses with correct data in withing 5-10 sec.
ItemPropertyService itemPropertyService = new ItemPropertyService();
foreach (ItemDto item in items)
{
itemPropertyService.GetItemProperties([parameters] , OnServiceCallCompleted);
ServiceSendCount++;
}
(Problem as i discussed it is going to send me 100 X 100 responses which leads to the timeout)
In Second Approch, (As per u have suggested)
foreach (ItemDto item in items)
{
ItemPropertyService itemPropertyService = new ItemPropertyService();
itemPropertyService.GetItemProperties([parameters] , OnServiceCallCompleted);
ServiceSendCount++;
}
I am getting same responses as of request, but it will take time near about 2 min.
Actually, I am not able to figure out the problem of time consuming.
As our requests are very huge it will really going to take time.
Do you know about this that how to solve this problem?
I am just near to solve my problem.
Can't tell from the code as you didn't show the ServiceCall() function but numbers suggest you are reusing the same proxy object and adding the OnServiceCallCompleted event handler every time you make a request. If you add the same event handler multiple times it is going to fire multiple times and the completed event handler is per proxy object not per request.
Try creating a new proxy object for each request and seeing if you still get multiple responses.