I am using PayPalAPIInterfaceClient (soap service) to get information about transaction (method GetTransactionDetails()) and need to be absolutely sure about transaction status (it means - money has been sent no matter in which direction).
When the transaction is really completed and when is still "on the road"?
For example: I assume, Processed will be followed by InProgress and finally changed to Completed or something like this. On the other hand, Denied or - I don't know - Voided will not change in future.
Can you help me please to decide, which status can be accepted as ultimate (like Completed, but may be even Completed must not mean final money transfer) and which ones are still in one of its sub-state?
I would expect simple "Money finally transferred" & "Money finally not transferred" result, but reality is different.
Shortly, to mirror transaction result into database and manage automatic transactions (from and to client) I need to know this.
I am using the PaymentStatusCodeType enumeration values and my service iterates transaction history to check if the money was transferred or not.
Completed means it's done. You may also want to look into Instant Payment Notification (IPN). It sends real-time updates when transactions hit your PayPal account so you can automate post-transaction tasks accordingly. This includes handling e-checks or other pending payments which won't complete for a few days, refunds, disputes, etc.
Related
There are tons of articles on 2 phase commit on the internet.
They are all saying the same thing and I am not getting it. I need a low-level understanding of it.
The orders and Payment service example is the most popular example on the internet.
Let's say we have Orders service and Payments service. When an order is placed, the Order service writes it to its database but the payment service must also write it to its own database in order for the transaction to be complete.
Here is my inadequate understanding:
User sends a place order request to Orchestrator
Orchestrator invokes Orders service to as well as Payment service at the same time. Now according to what I have read, Order and Payment services are supposed to respond to Orchestrator by telling it whether or not they are ready. What does that mean? What does it mean to be ready here?
Order and Payment service respond back, telling Orchestrator that they are "ready" (whatever that means).
Orchestrator sends another request to both the services (commit request).
Order writes the record to its database. The Payment service writes the record to its own database. They both respond back with status 200 to Orchestrator.
Orchestrator checks if both of the participants have returned status code 200. If yes, then it does nothing. If no then it asks them to ABORT?? How? One of the participants already wrote the transaction to its database.
Two-phase commit is all about handling failures and what they mean.
In phase 1, the orchestrator tells the order and payment services to prepare to commit. If everything goes well, they both respond with "prepared", which means:
The transaction is recorded durably, and marked prepared
There is no possibility that it will need to be rolled back due to conflicts or for any other reason, except the failure of some other service to prepare. Once the transaction is prepared, only the orchestrator can normally roll it back.
If both the order and payment processors successfully prepare, then the orchestrator will tell them finalize the commit. Finalized means:
The transaction is recorded durably and marked committed
It cannot be rolled back.
If anything goes wrong during this process, it's possible to check the durably recorded states of the transaction in both the payment and order services in order to determine whether it "really happened" and how to recover:
If not all of the services prepare successfully, then the transaction did not happen. The orchestrator will roll back the transaction in all the services that did prepare it. If things are broken, this may require manual intervention, or the orchestrator may not be able to complete this operation until things come back up.
If all of the services did prepare successfully, then the transaction did happen. The orchestrator will tell all the services that haven't finalized it to go ahead and do that. Again, this might have to wait until systems that are down come back up.
Also, sometimes it's not the orchestrator's job to recover. If the orchestrator gives up, then the individual services can check with each other to see if the transaction happened or not.
The important point is that once the two-phase commit starts, no matter what happens you can return the system to a consistent state by checking the durable transaction records.
In practice, two-phase commit is not used that often, because when transactions are in the prepared-but-not-finalized state, any other transactions that use their data cannot themselves commit, because they might need to be rolled back. This kind of contentions where transactions need to wait for each other slows the whole system down.
I will explain the steps of a successful purchase to you. The customer registers an order and then goes to the payment gateway and makes the payment there and returns to the store site and the payment record is recorded and the operator can track the steps.
Order table
Id int,
CustomerName nvarchar(150),
TotalPrice int,
SendState tinyint,
InsertDate datetime
Payment table
Id int,
OrderID int,
PayState tiniyint,
PayPrice int
The customer now registers an order in the database
Insert into Order values(1,'bill',30000,1,'5/1/2021 8:30:52 AM')
Now the customer connects to the payment gateway and makes the payment successfully and the store site returns.
Insert into Payment values(1,1,200,30000)
The results are now displayed for the operator
select o.*,p.PayState,p.PayPrice
from Order o join Payment p on o.Id = p.OrderId
If you do not pay, an error of 500 will be registered in the database and the operator, seeing the status of 500, will understand that the payment was not successful.
Insert into Payment values(1,1,500,0)
We have a system that receive payment information for invoices from the bank system. It works like that:
Invoice is created in our system
Payment for the invoice is done through Bank system. Bank system request invoice details from our system and it returns the invoice details
Bank system goes through payment process, and sends payment details to our system and it will wait for confirm message for 30 seconds. If the bank system does not receive confirm message within 30 seconds, bank cancels the payment but does not inform our system about cancellation.
Our system receives the payment info, and saves the payment. Then
sends the confirm message to bank. But sometimes, because of network
or system issue, confirm message won't be delivered within 30
seconds and we became unaware of cancelled message status.
So, the problem is our system saves the payment but sometimes cannot respond on time for payment confirmation request (within 30 secs), in this case, bank cancels the payment and our system doesn't know the payment is cancelled.
I have developed a solution that checks an each payment if the payment is successful (after 30 seconds of receiving the payment) by sending a request to check payment method Bank provided. Tasks (send the payment id to check_payment method of bank system - it returns payment status) are executed in separate threads using thread pool of Spring framework. But I am afraid that it is not the best solution as there is a risk of being full of thread pool when network failure happens .
What solutions would you recommend? Can we use RabbitMQ for this issue?
You are essentially implementing stateful orchestration. I would recommend looking into Cadence Workflow that capable of supporting your use case with minimal effort.
Cadence offers a lot of other advantages over using queues for task processing.
Built it exponential retries with unlimited expiration interval
Failure handling. For example it allows to execute a task that notifies another service if both updates couldn't succeed during a configured interval.
Support for long running heartbeating operations
Ability to implement complex task dependencies. For example to implement chaining of calls or compensation logic in case of unrecoverble failures (SAGA)
Gives complete visibility into current state of the update. For example when using queues all you know if there are some messages in a queue and you need additional DB to track the overall progress. With Cadence every event is recorded.
Ability to cancel an update in flight.
See the presentation that goes over Cadence programming model.
While learning payment technologies, I have reviewed some issuer's documentation about their implementation of ISO 8583, even though I have seen how this kind of messaging works, I have not completely understood how the Authorization Message (MTI x1xx) really works.
The general definition I have found is that this message 'determines if funds are available, get an approval but do not post to account for reconciliation', but I want to understand the general lifecycle of this message.
If the amount requested in the authorization is approved, does it mean that the funds are held until another message is sent? If the funds are not held, why reversal messages (MTI x4xx) offer the possibility of reversing the authorization? If another request is not sent, what about of 'not posting it for reconciliation'? Do issuers have to follow an expiration time as a standard to cancel the authorization request?
I know that these questions may depend on each issuer's specifications, but every time I search for the definition of the authorization message I always get the same one or two lines of description (like the one I wrote before) and no more.
I want to get a full explanation for this message and some examples. I really want to dominate this subject, because I do not want to use something that I do not understand.
Instead of using the terms issuer or acquirer, I usually prefer to use the term "payment processor" to refer to the institution or computer system that you communicate with in order to get process payments. As you know different payment processors do things differently, so I can only give you a general idea of how ISO 8583 is usually used.
When an authorization request or an authorization advice is approved, a temporary hold is usually put on the authorized funds. The authorization response message, that indicates approval, will usually contain an authorization number. I do not know how long the temporary hold on the funds lasts before it expires (or whether that time varies by payment processor).
The next step is to either:
Do nothing and let the hold expire.
Send a reversal message to reverse the authorization (and release the hold immediately).
Send a financial advice message, that contains the authorization number from the authorization response, to complete the transaction initiated by the authorization request/advice.
See the ISO 8583 Wikipedia page for background information
As far as my experience in the payment sector is concerned here is my explanation, I hope it could help you to some extent.
Most of the switches or payment systems use DMS (Dual Message System) for transactions, means in each transaction two request messages are sent from the acquirer (ATM) to the issuer (i.e. CBS). Both messages' type is x100, only some fields differ which differenciate them.
The first one is Authorization Request which is used to authorize the cardholder (i.e whether his/her PIN is correct or not, here all the basic validation and verifications are done) it is called precheck. In this case, no amount is held on the CBS and no reversal message is required in case the transaction fails.
The second one is the actual transaction request message (i.e balance inquiry, cash withdrawal and etc..). In case of cash withdrawal, the acquirer requests the issuer for cash withdrawal (the routing is done through a switch or a payment system).
As the user is already authorized, but there is no response from the issuer or it is a timeout. There can be lots possibilities why the transaction failed or no response is received.
The amount is debited from the customer in CBS but due to internet
issue the resposne is not received by the aquier (ATM).
The amoutn is debeited from the customer, but due to load of process
in CBS the acquierer received response late (there is a time limit within
the switch should receive response from CBS called timeout i.e 10 secenods or 15
seconds etc. each switch has its own rules and setting for timeout).
In above secnarios, the switch (SV, CSC, etc.) sends reversal advice (MTI x420) to the CBS or reversal advice repeat (MTI x421) after 5 seconds in case no response is received for reversal advice.
Then, the issuer (CBS) sends reversal response (MTI x430) which means the transaction is reverted (the amount is credited back to the account/ card) successfully.
This is the end. Both parties (issuer and acquirer) will be happy and there will be no money loss or fraud.
NOTE:
- x in MTI determines the ISO 8583 version.
- MTI stands for Message Type Identifier
What is the best way to achieve DB consistency in microservice-based systems?
At the GOTO in Berlin, Martin Fowler was talking about microservices and one "rule" he mentioned was to keep "per-service" databases, which means that services cannot directly connect to a DB "owned" by another service.
This is super-nice and elegant but in practice it becomes a bit tricky. Suppose that you have a few services:
a frontend
an order-management service
a loyalty-program service
Now, a customer make a purchase on your frontend, which will call the order management service, which will save everything in the DB -- no problem. At this point, there will also be a call to the loyalty-program service so that it credits / debits points from your account.
Now, when everything is on the same DB / DB server it all becomes easy since you can run everything in one transaction: if the loyalty program service fails to write to the DB we can roll the whole thing back.
When we do DB operations throughout multiple services this isn't possible, as we don't rely on one connection / take advantage of running a single transaction.
What are the best patterns to keep things consistent and live a happy life?
I'm quite eager to hear your suggestions!..and thanks in advance!
This is super-nice and elegant but in practice it becomes a bit tricky
What it means "in practice" is that you need to design your microservices in such a way that the necessary business consistency is fulfilled when following the rule:
that services cannot directly connect to a DB "owned" by another service.
In other words - don't make any assumptions about their responsibilities and change the boundaries as needed until you can find a way to make that work.
Now, to your question:
What are the best patterns to keep things consistent and live a happy life?
For things that don't require immediate consistency, and updating loyalty points seems to fall in that category, you could use a reliable pub/sub pattern to dispatch events from one microservice to be processed by others. The reliable bit is that you'd want good retries, rollback, and idempotence (or transactionality) for the event processing stuff.
If you're running on .NET some examples of infrastructure that support this kind of reliability include NServiceBus and MassTransit. Full disclosure - I'm the founder of NServiceBus.
Update: Following comments regarding concerns about the loyalty points: "if balance updates are processed with delay, a customer may actually be able to order more items than they have points for".
Many people struggle with these kinds of requirements for strong consistency. The thing is that these kinds of scenarios can usually be dealt with by introducing additional rules, like if a user ends up with negative loyalty points notify them. If T goes by without the loyalty points being sorted out, notify the user that they will be charged M based on some conversion rate. This policy should be visible to customers when they use points to purchase stuff.
I don’t usually deal with microservices, and this might not be a good way of doing things, but here’s an idea:
To restate the problem, the system consists of three independent-but-communicating parts: the frontend, the order-management backend, and the loyalty-program backend. The frontend wants to make sure some state is saved in both the order-management backend and the loyalty-program backend.
One possible solution would be to implement some type of two-phase commit:
First, the frontend places a record in its own database with all the data. Call this the frontend record.
The frontend asks the order-management backend for a transaction ID, and passes it whatever data it would need to complete the action. The order-management backend stores this data in a staging area, associating with it a fresh transaction ID and returning that to the frontend.
The order-management transaction ID is stored as part of the frontend record.
The frontend asks the loyalty-program backend for a transaction ID, and passes it whatever data it would need to complete the action. The loyalty-program backend stores this data in a staging area, associating with it a fresh transaction ID and returning that to the frontend.
The loyalty-program transaction ID is stored as part of the frontend record.
The frontend tells the order-management backend to finalize the transaction associated with the transaction ID the frontend stored.
The frontend tells the loyalty-program backend to finalize the transaction associated with the transaction ID the frontend stored.
The frontend deletes its frontend record.
If this is implemented, the changes will not necessarily be atomic, but it will be eventually consistent. Let’s think of the places it could fail:
If it fails in the first step, no data will change.
If it fails in the second, third, fourth, or fifth, when the system comes back online it can scan through all frontend records, looking for records without an associated transaction ID (of either type). If it comes across any such record, it can replay beginning at step 2. (If there is a failure in step 3 or 5, there will be some abandoned records left in the backends, but it is never moved out of the staging area so it is OK.)
If it fails in the sixth, seventh, or eighth step, when the system comes back online it can look for all frontend records with both transaction IDs filled in. It can then query the backends to see the state of these transactions—committed or uncommitted. Depending on which have been committed, it can resume from the appropriate step.
I agree with what #Udi Dahan said. Just want to add to his answer.
I think you need to persist the request to the loyalty program so that if it fails it can be done at some other point. There are various ways to word/do this.
1) Make the loyalty program API failure recoverable. That is to say it can persist requests so that they do not get lost and can be recovered (re-executed) at some later point.
2) Execute the loyalty program requests asynchronously. That is to say, persist the request somewhere first then allow the service to read it from this persisted store. Only remove from the persisted store when successfully executed.
3) Do what Udi said, and place it on a good queue (pub/sub pattern to be exact). This usually requires that the subscriber do one of two things... either persist the request before removing from the queue (goto 1) --OR-- first borrow the request from the queue, then after successfully processing the request, have the request removed from the queue (this is my preference).
All three accomplish the same thing. They move the request to a persisted place where it can be worked on till successful completion. The request is never lost, and retried if necessary till a satisfactory state is reached.
I like to use the example of a relay race. Each service or piece of code must take hold and ownership of the request before allowing the previous piece of code to let go of it. Once it's handed off, the current owner must not lose the request till it gets processed or handed off to some other piece of code.
Even for distributed transactions you can get into "transaction in doubt status" if one of the participants crashes in the midst of the transaction. If you design the services as idempotent operation then life becomes a bit easier. One can write programs to fulfill business conditions without XA. Pat Helland has written excellent paper on this called "Life Beyond XA". Basically the approach is to make as minimum assumptions about remote entities as possible. He also illustrated an approach called Open Nested Transactions (http://www.cidrdb.org/cidr2013/Papers/CIDR13_Paper142.pdf) to model business processes. In this specific case, Purchase transaction would be top level flow and loyalty and order management will be next level flows. The trick is to crate granular services as idempotent services with compensation logic. So if any thing fails anywhere in the flow, individual services can compensate for it. So e.g. if order fails for some reason, loyalty can deduct the accrued point for that purchase.
Other approach is to model using eventual consistency using CALM or CRDTs. I've written a blog to highlight using CALM in real life - http://shripad-agashe.github.io/2015/08/Art-Of-Disorderly-Programming May be it will help you.
I am writing a bitcoin app and looking to implement a 'cancel' feature. All over reddit are references that if under 3 confirmation have occurred, technically a payment can be stopped. Maybe only a minute or 2 available, but still.
I cannot find any reference in the bitcoin api docs to demonstrate how this would be done.
I know that one altcoin uses an intentional 60 min gap to confirm for this very reason.
Anyone know how this is done?
Is it possible to cancel a Bitcoin transaction ...
... which was not yet broadcasted?
Yes, obviously it is possible. I'd propose you choose this method in your Bitcoin app by showing the user a confirmation screen for some seconds with information about the transaction and some buttons saying cancel and confirm. #nahtnam proposed a 60 minute delay which is too much, considering you may lose internet access or want the transaction to appear in the blockchain as soon as possible.
... which was already broadcasted?
Maybe... To cancel such a transaction, you'd need to create a block yourself which moves the inputs of the original transaction to one of your own addresses. (Effectively invalidating the original transaction.) However, creating a block costs several thousand dollars as of now and finding a block is not guaranteed.
Another possibility would be to broadcast another transaction taking the same inputs as the original one and targeting the outputs at one of your own addresses/wallets. To motivate miners to include this transaction instead of the original one, you increase the transaction fee. However, some clients may not relay such double spent transaction to the miners and some miners may reject the double spent transaction and include the original one (the one they received first), instead. (c.f. Bitpay encountered zero double spent in the first 10000 transactions. and Cancelling an unconfirmed transaction by #theymos (bitcoin.stackexchange))
There are some tricks to hide your initial transaction from miners by creating a so-called "non-standard" transaction. Alternatively, the transaction could include a very low fee to make miners reject it for economic reasons. (c.f. Significant losses by double-spending unconfirmed transactions (bitcoin-dev mailing list) and Double-spending by #petertodd (Reddit)) However, this makes your transaction look suspicious to the receiver if they look closer at it and they will most likely ask you to wait until it has one or more confirmations.
Finally, it is also possible if you set a flag on the original transaction to indicate replaceability. You can then replace the original transaction with another one by including the same (one or more) inputs in the replacement transaction. Also, you must pay a higher fee. However, not all miners honour this flag and some might still include your initial transaction. (c.f. Reference to BIP 125: Opt-in Full Replace-by-Fee Signaling)
... which is included in one or more blocks?
No, very unlikely to impossible. You'd need to control a substantial amount of hashing power to create a fork by rebuilding the blockchain starting at the block before the original transaction happened and ending at the block with height = (current public blockchain height) + 1. Therefore, "the more confirmations you have, the more difficult, expensive, and unreliable an attack like this is."
Source: #DannyHamilton (Bitcointalk)
The bitcoin paper by Satoshi Nakamoto explains that this is always possible when you control more than 50% of the hashing power, and possible with a probability less than 1, but greater than 0, if you control less than 50% hashing power. See Bitcoin: A Peer-to-Peer Electronic Cash System.
Though, if you control a substantial amount of hashing power, you are likely incentivised to not undermine the trust in bitcoin by undoing transactions and indirectly hurting your revenue stream from mining.
No. It is impossible to stop a bitcoin transaction. Thats what makes bitcoin so different. There is no way to reverse a transaction except for getting the receiver to send it back to you.
On another note, you could still have a cancel feature. You could set a delay of 60 minutes before you send a transaction and in that gap, someone can cancel but as I mentioned before there is no way to stop a transaction that has already reached the blockchain.
Work out the strategy before making a bitcoin payment. Check that both bitcoin addresses for payer and recipient are correct (use the copy and paste facility). Check that details of the product/service and $ amount are correct. Check that you have the correct private key details. Expect to wait at least 24 hours for confirmation. This allows time for the miners to validate the transaction. Then check your bitcoin account to ensure that the transaction is completed correctly by inserting your private key details into Google search, or check your bitcoin software for the transaction details.
It is complicated and expensive to cancel a transaction. So before you make payment, check, check and check again before sending.