Project background

Recently, due to project business reasons, we need to design recharge and consumption functions of virtual currency for the system. There are mature payment gateway services in the company, so the focus becomes how to design the recharge process of virtual currency in the project, so that the whole recharge process is idempotent, so as to ensure that users’ virtual currency balance will not be repeatedly increased or deducted.

Product purchase and payment process

  1. When the user purchases goods, the merchant background requests to generate payment orders and returns relevant information to the client.
  2. The client invokes the payment SDK based on the returned information, and the user confirms the payment.
  3. After the user completes the payment, the payment system will asynchronously inform the merchant background of the payment result.
  4. The merchant background receives the payment callback and completes its own business logic in the callback interface.
  5. After the payment is completed, the client will delay a certain time to query the payment result from the merchant background. At this time, if the payment callback has not been received, the client can take the initiative to synchronize the payment result (bottom guarantee strategy).

The alipay payment process is similar to wechat Payment, which is omitted here. Normally payment callbacks are notification callbacks at the millisecond level.

Virtual currency recharge process

The virtual coin recharge process will be nested in the payment callback process. If the virtual currency does not complete the business process, the payment system will retry. So business processes need to support idempotent.

  1. How to support order breakdown by user dimension? The payment callback information only includes the order ID information, in which case it is generally only possible to table by order ID. In view of the increasing number of orders, we began to break down the orders by user dimension. In general, there are many queries based on the user dimension, while there are few queries based solely on the order dimension. Therefore, the user ID information is written into attach additional information when pre-ordering, and the original additional information will be carried in the payment callback, so that the user and order ID information can be known and the subsequent operations can be completed.

In the later optimization, when the order ID is generated, the low level section is reserved to store the user’s order table ID information, so that the transmission does not rely on additional information completely, and the callback notification when the user conducts automatic fee deduction authorization can also be applied.

  1. How does virtual currency do transaction operations? If only the user virtual currency quantity information, it is easy to repeat the wrong operation. Therefore, the flow table is required to cooperate with transaction operations. If the flow table has the same record, the current operation is repeated and the virtual currency value needs to be rolled back. The correct change of virtual currency can be realized through the single database transaction, and reentrant is supported.
  2. How to do the version control of virtual currency? Each change of our virtual currency will correspond to a version number. In the concurrent operation of virtual currency, data changes are generally made by judging whether the version meets expectations. This is similar to optimistic lock control, but deadlocks are more likely to occur in this case, especially if database performance is poor. Therefore, the version number is not strictly determined. You only need to change the number of virtual coins not less than 0. All changes that meet this condition are considered valid changes. This scenario is suitable for data security verification without version number, which is suitable for inventory model and has higher performance.
update table_xxx set avai_amount=avai_amount+:deltaAmount where user_id=:userId and avai_amount+:deltaAmount >= 0
Copy the code

In most cases, only virtual currency consumption will have concurrent modification, so we just need to strictly control the virtual currency balance will not be insufficient to deduct.

Apple purchase virtual currency recharge process

When a user makes an in-app purchase, the client can obtain the user ID, transaction receipt and transaction ID. There is a big difference between the overall purchase process and the Android end, because the receipt verification process refers to the Android ordering process, which makes it easier to reenter.

  1. The client obtains the recharge list;
  2. After successful payment, the client submits transaction voucher receipt to the server for verification. The server creates corresponding voucher and order record, updates the status and completes recharge.

Apple internal purchase matters needing attention

  1. How can I avoid receipt being reused? After successful payment, the iOS client can obtain transactionId and receipt information, which are uniquely corresponding. Therefore, after verifying that the receipt is valid, the server can create a corresponding transaction record, which is segmented according to the transactionId, with the transactionId as the unique key. This prevents the receipt from being reused.
  2. Mapping between Transaction and order record? The order record contains the channel transactionId information so that it can be uniquely bound to the order information after the transaction record is created, avoiding the repeated creation of the order.

Design summary

When designing the order system, idempotence is the primary consideration. It is necessary to ensure the accuracy of the amount strictly and not to deduct or pay more money to users. In general, we improve the robustness of the order system by means of database single machine transaction and idempotent retry.