Microservices out of sync - ruby-on-rails

Application architecture has three microservices; let's call them A, B, and C.
A is the authority for holding user permissions (including permissions for sending SMS) and when permissions update it publishes an Event for services interested in this data.
B and C listen for permissions changes, to control sending SMS.
Main Rails App is integrating with A, B, C.
App updated A with permissions to prevent student A from receiving any SMS,
and then A published the event which gets delayed in Queueworker;
App started to send SMS through B, which is not updated yet because of Queueworker delay.
How can we ensure (or what is need to be changed in design to ensure) users will not receive SMS once permissions changed to false?

You're running into the biggest challenge of distributed systems -- the CAP theorem. To summarize, a distributed system (like you have) can never guarantee all three of the below:
Consistency - all services see the same data at the same time
Availability - all services' requests to each other receive a success or failure response
Partition tolerance - the system continues to function even when services cannot reach each other
In your specific problem, the lack of consistency is hurting you. You can fix it, but you'll have to give up one of the other points. For example, before sending each SMS, you could have service B perform a synchronous HTTP request to service A to verify that the intended recipient still has permissions to receive SMSes. This will fix your consistency issue, but creates a dependency that A must be up and running for B to function (meaning, you've lost the P from CAP).
You could also mitigate the issue by sending SMS requests as events through the same queue that the permission updates go through. It's still possible for an SMS to send after the permission was disabled, but that would only happen if the permission update came in after the SMS was meant to be sent. This is still lacking consistency, but the impact is less severe (at a cost of SMS latency).

Related

What is my best bet on periodically running a task to update Live Activity when my app is in the background?

I have an idea for an app that utilises Live Activities, inspired by the Flightly app (it starts a Live Activity for a plane ride): Basically I wanna use open data from an HTTP endpoint that is reachable via the onboard WiFi on a bus. E.g. you board the bus, connect to the onboard WiFi, open the app, it fetches details about the stops and then you start a Live Activity guiding you to a selected stop. So far so good. But sometimes the bus faces delays, etc. In that case, I need to update the Live Activity. That is easy when my app is running. It is not so easy, when my app is not running (or running in the background).
What is my best approach to regularly fetching data from the endpoint and updating my Live Activity? The problem is, that the endpoint is only reachable on the buses WiFi. So it looks like I cannot use APNS to push updates to the Live Activity (since my service running outside the bus cannot access the endpoint that provides the details and thus cannot push any meaningful updates). Background Tasks (e.g. background app refresh) run infrequently.
What options are left? I thought about receiving location updates in the background and acting on them to update my app state (and possible the Live Activity, if needed), although I haven't investigated that path in detail, yet.
Has anybody faced a similar issue and found a solution or can provide some guidance on how to approach this problem?
I think the easiest option is core location. So keep your application running by monitoring the position and then you can update the Live Activity by fetching the information from your access point. It should be fine for app review since you could use the the location to show a position on a map and only while the person is on the bus.
If your application isn't running you have to send the ActivityAttributes via APNS. Since the data cannot be accessed from a remote server that would communicate with APNS there is no direct way to use ActivityKit push notifications. An indirect approach (which I would not recommend) would be to send silent push notifications triggers every 5min or so and fetch the newest information when the application is woken up. But this won't work when the app is force-quit and using silent pushes to trigger polling will give you a bad score by the system and eventually the frequency will be throttled from APNS.

Websockets vs. iOS Push Notifications

Take an iOS app like Instagram. Instagram is fundementally a real-time application that updates its UI whenever a user interacts with you. For example, if someone likes your post and you are using the app, the UI is updated to trigger dopamine release and inform you that something has hapened to one of your posts. Similarly, when someone sends you a direct message on instagram, while using the app, you see the message spring down from the top, all in real-time.
In terms of implementing such real time features it is obvious that a naive HTTPS polling approach is far too inefficient. Thus this leaves two strategies:
1.) APNS Push Notifications:
When a user likes a post, sends a direct message, comments (etc.), send an HTTP POST to a backend server that will then update the database and send a silent Apple push-notification to the device of the recipient. The recipient, which is using the app, will receive the pushed payload and will send an HTTP GET to the backend server to fetch the needed data (ie. the contents of the direct message sent). The UI is updated in quasi "real-time".
2.) Websockets:
Whenever any user opens the iOS app, connect the user to the server via a websocket. This means, that all users currently using the app are connected to the server via their own websocket. When a user likes a post, sends a direct message, comments (etc.), the app sends a message to the server through the socket indicating the action. The server, before updating the database, finds the socket associated with the recipient and forwards the message through the socket to the recipient. Upon reception of the message, the UI is updated in real-time
Which of these approaches is scalable and better suited for a production environment?
TL;DR You'll love websockets + Combine framework, event driven to update your UI smoothly. APNS can be somewhat unreliable in terms of deliverability and resource/database costs, and to me is more of an information center.
Reasons to like websockets:
Decreases DB costs (e.g. finding device to send to)
You know when the user is not using the app, decreasing outbound data costs
Latency and faster practically speaking (more in depth in the websocket paragraph)
To answer the question: websockets are scalable based on your user count obviously. APNS is not server side testable in the CI, not cross platform, and not exactly feasible in terms of resource consumption.
I have a bias with websockets. But to present why I like it more, think about the efficiency given by your Instagram example.
To me, websockets == Event Driven, APNS is a simple information center.
APNS:
You sign up with APNS and you save the device in your backend. Great, every time an action is performed, like someone liking your post, query your backend, find the device that is linked to the OP, then send it outbound (which costs money if you think cloud computing costs). And you have to do that every single time someone likes your post (obviously you can aggregate, but why bother when you have websockets?). So database costs is one thing to think about. Additionally, a user could be muting their notifications. I don't have Instagram, but something efficiency wise they could have done (if not by sockets) is updating their UI based on incoming notifications for likes/hearts rather than a websocket connection. That's slow in terms of latency, costly, and unreliable if marked as spam. However, APNS has the benefit of not needing authorization unlike websockets, but...
Websockets:
When we approach websockets, you only authorize once (at least for mobile applications). You're removing outbound data costs (in terms of $$ and latency) by removing stuff like headers. You want to send small chunks of data, and sockets are just sending text/binary (I like to create commands out of them using JSON. A notable example is GitHub). When your user is done with the app, you close the connection and you don't need to send anymore data via APNS. Your server itself can be communicating with a single websocket via something like Redis PubSub in order to update your UI when someone uses a POST request to heart a post without needing to send some push notification. That's a win for the liker (who doesn't need to wait for that push notification to be sent) or the other way if you offload it to a background task (the OP doesn't need to wait). Websockets == Event Driven:
Small data chunks that are constantly delivered (as in a lot) is much better than having APNS in which it can be slow to actually deliver, especially if you're flooding Apple/your user with notifications, marking you as spam. Although, disclaimer, that's just my personal belief and speculation depending on your use case.
You're removing those unnecessary database costs.
A downside would be keeping the connection alive.
Personally, I've used websockets with the combine framework recently for a chat application, but it can be used in so many different circumstances. Updating a Facebook feed/comment section, live notifications via the websocket instead of APNS, even posting content.
APNS is not guaranteed to be delivered, especially if you have a lot of notifications - I don't remember where I read that, but after some threshold per min it'll stop working. Also, you'll have to send them to all your users, not just online ones. It's possible to send silent notifications, but it's still not optimal.
That's why websocket is a preferred way. Also you can use something like https://github.com/centrifugal/centrifugo, which is a helper for your server, that'll hold all the connections, and is very stable.
It is not one out of two, even the web-socket isn't failsafe, but all of above should be considered for an effective communication, when the app is in foreground use a web-socket to listen for any updates from the server, expect a confirmation from client when something is delivered by socket, if the web-socket connection is not active or the there is no confirmation response deliver the update through APNS/FCM, as APNS/FCM it is not guaranteed to deliver, deliver the updates when next Socket connection is successful.

iOS: Unable to fetch Offline messages for XMPP Chat

I am facing an issue with the presence status, following the documentation and XMPPframework example code. I have written a chat application.
Problem : When the user 1 & 2 are online I get the status successfully and they can chat with each other. However when the user 2 goes physically offline via (Wifi OFF / 3G Off) User 1 is not getting the offline status from XMPP and hence what ever messages are sent from that instant of time are lost when the user 2 comes online.
It seems since the user 2 is not notified or stored as offline in XMPP and hence its not storing the offline messages to push back to user 2 when it comes online.
I have tried to resolve this by explicitly writing a [goOffline] call to XMPP, however the call is shown in 'SEND log' for 'user 2' but not received in 'RECV log' in user 1 from XMPP, due to which the message are lost in between.
Also tried with other sources replies.
Set status for presence available and send XMPP
priority changed with values non-negative
XMPPArchiving work but this is not what I wanted.
Server side Mod_zero push enables but get only first message push notification sometimes.
Setting limit on ejabberd.cfg file for users and offline message limit.
request for offline message pull.
Can anyone help me with this?
This is very typical situation where client losses network but server can't detect that it is offline.
To detect status of each client, server need to send PING packets to every client and wait for response.
If client responds then fine otherwise server will mark that client as offline and every other online client will be informed automatically.
Here is PING Module implementation for ejabberd XMPP Server (hope you are using ejabberd server):
mod_ping:
send_pings: true
ping_interval: 10
timeout_action: kill
ping_ack_timeout: 10
This has to be written in ejabberd.yml configuration file.
At client side also we need to enable ping module to respond to server pings as:
private var xmppPing: XMPPPing?
xmppPing = XMPPPing()
xmppPing!.activate(xmppStream!)
This code has to be written while we setupStream() for iOS.
For detailed info, please go through mod_ping documentations.
Sounds like your problem is at server level. The server thinks that the user is online so it sends the message but nobody gets it. This does not really have a simple solution.
1.
The best solution would be delivery receipts. Where basically when the message is sent to your client, your client returns a confirmation of delivery receipt. If the server does not get that receipt it would resend the message every n time. Depending on your XMPP server you might find a already made solution, of not you would have to roll out your own.
2.
A possible hack would be to have your server always store and deliver last 10 messages and then at client side you discard repeated... This also depends on your server implementation. XMPP MUC and PubSub have resources along these lines.
For a long term scalable solution, you'll need to deal with this both at server and client level.

How to notify a Cab or Taxi Operator using GPS

Using GPS, how can I notify a cab operator in the area if I wanted to be fetched? I've seen a lot of apps regarding finding a taxi and fetch you wherever you are, example http://www.taxifinder.com/ .
I'm wondering what's the idea behind it?
Does the cab operator need to have a server where I can access it and tell them I need a taxi?
I really don't know how to do it, can someone enlighten me. Steps / list on how it should be done.
I don't know the scalability of it but here is a try:
A webserver that can process the request from the frontend and processes it. A simple case scenario would be that it receives the requestor's information including GPS coordinates. It would then check for drivers in the vicinity that are registered to the webserver and dispatch the push notifications to them.
A push notification system to push the notification to the cab driver/s. Check out Google Cloud Messaging although I believe there are no options for filtering the users in this case.
A web/native application that communicated with the server.
ps. The Taxi driver/s will have to have their devices registered for the push notification. On a second thought, the Taxi driver[s]' location access would be required as well so as to filter the drivers that would receive the dispatch request. Then maybe add a functionality where if one driver 'accepts' the dispatch, the user is notified and the other drivers cannot accept it any more.

Suggtestions for sending e-mail notifications from a 2 tier application with client potentially not connected to the internet

I have to add e-mail notifications to a client server application.
Notifications happen as the user do some particular action on the client UI.
If I had a middle tier or a service running at server I can imagine how to do it:
1) I simply create a DB tables with "pending notifications"
2) as a user does an action that generates a notification I add a record to the table
3) serverside I would continuously try to send those mails and removing them from the table once sending is succesful
Now I cannot do this now, I have a plan to add a service later on, but for now I must go the quick and dirty way.
So somehow what I was thinking to is to implement something like this:
1) as a notify-worth event occurs at client, the same client (my exe) tries to send the notification, upon failure it will log the notification in the "pending notifications" table (failure can be becuase lack of internet connection or any other problem)
2) I add a Timer that will work from any client machine to check for pending notifications. If there are any the client will try to send the e-mail (using a transaction: I will mark a field as "TryngToSendFromClientX" and in case of failure I will reset that field to NULL)
I think this approach would work, it has obvious limitations (if after failure no one logs into the system, no notification will be sent - same would be if service goes "down"). But can you comment on this approach and suggest a better one?
Additional notes (to better understand the scenario):
a) Note: all notifications are sent from the same e-mail account.
b) I don't need to keep track of who sent the e-mail.
c) the problem of creating the service now is that it will basically complicate significantly deployment and I need to create tools for monitoring the status of the service. Something that I will do in future but not now, in future I have plan to add more functionality (not only sending notifications) to the service, so in that case it makes more sense to create it.
d) I will send e-mails by using Indy components and SMTP server.
If you are not willing to create the service now, I think you are stuck with the scenario you describe. There are some things though you could do to circumvent the problem of no user firing up the client anymore while there are still pending messages.
You could add a commandline utility (or commandline parameter as bepe4711 suggested) that will only check for pending messages and try to send them.
Add this commandline utility to the StartUp folder or Run key in the registry. This way messages will at least get sent when the computer restarts, even if the user does not fire up the your app.
Add a scheduled task to run this utility at least once every day. The scheduled task can be added by code or by your installer.
If you do both, you will only have to worry about pending messages of users that never start their computer again.
Perhaps you can add a parameter to your client which causes it to just look at the pending notifications and send them. After this it can terminate itself. It will just act like some kind of service.
Then you install the client on the server and start it every x minutes.
I do something very similar to the approach you describe. Instead of sending emails I need to call a web service. My application is installed on several laptops and they are commonly not connected to any network.
When my application raises an exception I collect various bits of information including user comments and screen shots. Then I attempt to send this to our web service. If by chance the web service is not available. (i.e. not connected to the internet or web service is down) I write the results to an XML file on disk in the User Profile (App_Data) directory.
The one major difference is I don't poll to check to see if the server is up. I attempt to send them again on the startup of the application.
If both Systems are running on Windows, have a look at MS Message Queue. It is designed to send notifications to systems, which are not allways online. I did it in .Net, there are already easy to use classes implemented. Not sure about Delphi.
Latest version of Windows uses much more the Windows Task Scheduler, and now task can be fired on event (i.e. when a network card gets connected...). You could write a separate utility that tries to send pending notification, even if noone is logged in.

Resources