The background,

Official website mall in double 11, double 12 and other promotion period operation students will carefully design many promotional activities to user welfare, when more and more promotional activities will involve a lot of operation configuration work (such as the specified activity validity period, the specified activity start and stop state, the specified activity to participate in the commodities, etc.).

If for some reason lead to some of the configuration is not as expected configuration, wait to big for the moment to find configuration not properly configured, such a big probability will be lost a lot of orders, also may appear mismatches preferential cause some shouldn’t enjoy preferential were users enjoy, could lead to big losses to the mall, Therefore, in order to minimize the probability of the occurrence of these situations, we want to provide an ability for operators to check whether all the expected discounts are correctly configured before the important e-commerce promotion officially starts.

Second, the conception of

Want to let the operation students to check whether the big promotion discount is normal, and at the same time hope not to add extra work, how to do it?

Considering the particularity of e-commerce business, all kinds of big promotion discounts configured will be mainly reflected in the price after the discount, so we consider to achieve it from this perspective.

In the core link of e-commerce, there are mainly several core scenarios, such as business detail page, shopping cart, order confirmation and order submission. Therefore, it is only necessary to see the price after the discount in advance in these scenarios to judge whether the big promotion discount is correctly configured.

So now the key question is how to achieve “in advance” see? In the previous promotion series, we introduced the construction of a billing center, which centralized all the preferential pricing computing capacity, so we just need to let the billing center provide “advance” capacity.

Valuation center normal will only offer real-time calculation current time can enjoy various preferential goods, and will eventually offer tell upstream business, so we can let valuation center to calculate the preferential price “a future point in time”, when calculating the preferential price and valuation center, relying on a key information is * * the current time, Therefore, we only need to “tamper” the so-called “present time” into some point in the future to achieve the purpose of our so-called time travel.

There is also a very important point to pay attention to, which is also the premise of this ability to pass through, is not to affect the normal online transactions, that is, not to allow normal ordinary users to see the future discount price “in advance”.

So how to make the operating experience without affecting normal users? We are considering whitelisting so that only logged-in users with a whitelisted user ID can have the so-called traversal experience.

With the general idea in mind, there are a few questions to confirm:

Is there only a mall shopping process for the complete experience of travel?

If you need to experience all the atmosphere of the whole official website mall during the promotion period, there may be more changes involved, such as the promotion campaign page, exclusive aggregation product page, the simplified version only focuses on the whole shopping order process.

Does the entire traversal actually require the creation of an order?

After time travel, the user’s order time and order confirmation time is the same, so the confirmation page of all offers and the final price is the real WYSIWYG, without the real order can be informed of all offers information

Therefore, when submitting an order, it is recommended to directly block and remind the user “you are currently in time travel, please return to reality and place an order again”. It does not create a real order, and it will not make many subsequent chain operations to write resources. At the same time, in this case, it will reduce a lot of unnecessary changes.

Is it necessary to make special identification for the user special coupons received during the crossing?

A) If there is a special mark on the coupons received during the time travel, it is suggested not to use the coupons after exiting the time machine and after the actual coupon availability period, so as to prevent occupying the resources of ordinary users. In this case, it is also not recommended to increase the number of coupons issued.

B) If there is no special mark on the coupons received during the travel, then the coupons used after exiting the time machine are no different from other coupons received normally. This situation is considered to occupy the resources of ordinary users, so it is suggested to increase the number of coupons issued accordingly.

Plan A requires adaptation of the coupon system, but there is no pollution or occupation of online real resources; Plan B does not require any change, but it will occupy a very small amount of real resources. If the operator thinks the problem is not big, it is recommended to adopt Plan B, which has the lowest cost from the perspective of the project.

Three, implementation,

3.1 Core Flow Chart

According to the above scheme, the following mall through the core shopping process:

3.2 Key points of transformation

The key points of the transformation can be seen from the above flow chart:

  • Maintain whitelist information

  • Get “Current Time”

3.2.1 Maintaining Whitelist Information

In order to facilitate the time information sharing of travel users in the future, we store this information (openId: travelTime) in the configuration center, and provide the corresponding management console to facilitate the setting of travel users and travelTime points.

3.2.2 Obtaining The Current Time

The entire upstream and downstream associated systems may need to obtain ** Current Time. To obtain current Time, you need to obtain the configured whitelist and current user information. Obviously, in order for each business system to minimize code changes, obtaining the “current time” fits into a common module that each business system relies on to automatically obtain the expected “current time” **.

Therefore, the link relationship of the entire business system after the integration of the time machine module is shown as follows:

3.2.3 Time machine modules

From the foregoing, we can conclude the main capabilities that need to be included in vivo XXX-time-travel:

  • A) Traversing user whitelist information

  • B) Get “Current time”

  • C) Read and set context openId

The implementation of a and B is relatively simple. You only need to access the configuration center of the company and obtain ** “current time” according to the specified openId. What is more troublesome is to obtain the user openId information when the “current time” is **.

Before, the interface call between various service systems may not require user openId information, but now the traversal user is specified as a whitelist user, so the user openId information detected by the inlet link must be transmitted all the way down to each downstream service system.

** Scheme 1: ** Indirect call of all business systems is coupled with openId information, which requires all business systems to be transformed. Obviously, this scheme is relatively primitive and unfriendly to all business parties, so it is not recommended to adopt it. Scheme 2: Since dubbo is used to make interface calls between various back-end business systems, we can use duBBo’s customized business filter based on SPI plug-in mechanism to pass through openId as additional information when the additional interface is called. (If it is called by other interfaces, it is also recommended to adopt a similar principle.)

Let’s take a look at some of the core code implementations in the time machine module :(filters executed when the current business system is the consumer)

Filters that are executed when the current business system is the consumer

/** * @activate (group = Constants.CONSUMER) public class BizConsumerFilter implements Filter { @Override public Result invoke(Invoker<? > invoker, Invocation invocation) throws RpcException { if (invocation instanceof RpcInvocation) { String openId = invocation.getAttachment("tc_xxx_travel_openId"); if (openId == null && TimeTravelUtil.getContextOpenId() ! = null) {// as a consumer before invoking, If openId is missing, set the openId ((RpcInvocation) Invocation). SetAttachment (openIdAttachmentKey, TimeTravelUtil.getContextOpenId()); } } return invoker.invoke(invocation); }}Copy the code

Filters that the current business system executes as a service provider;

/** * @activate (group = Constants.PROVIDER) public class BizProviderFilter implements Filter {/** @activate (group = Constants.PROVIDER) public class BizProviderFilter implements Filter { @Override public Result invoke(Invoker<? > invoker, Invocation invocation) throws RpcException { if (invocation instanceof RpcInvocation) { String openId = invocation.getAttachment("tc_xxx_travel_openId"); if (openId ! = null) {/ / as the downstream service provider, to obtain the upstream system setting the context of the openId TimeTravelUtil. SetContextOpenId (openId); } } try { return invoker.invoke(invocation); } finally { TimeTravelUtil.removeContextOpenId(); }}}Copy the code

Get utility classes through time;

Public final class TimeTravelUtil {private static final ThreadLocal<TimeTravelInfo> currentUserTimeTravelInfoThreadLocal = new ThreadLocal<>(); private static final ThreadLocal<String> contextOpenId = new ThreadLocal<>(); public static void setContextOpenId(String openId) { contextOpenId.set(openId); setUserTravelInfoIfExists(openId); } public static String getContextOpenId() { return contextOpenId.get(); } public static void removeContextOpenId() { contextOpenId.remove(); removeUserTimeTravelInfo(); } /** * Sets the current context user traversal information, If any * @ param openId * / public static void setUserTravelInfoIfExists (String openId) {/ / TimeTravellersConfig access configuration center, Carry all whitelists through the user information configuration, And converts each through the user information to TimeTravelInfo TimeTravelInfo userTimeTravelInfo = TimeTravellersConfig. GetUserTimeTravelInfo (openId); if (userTimeTravelInfo.isInTravel()) { currentUserTimeTravelInfoThreadLocal.set(userTimeTravelInfo); }} public static void removeUserTimeTravelInfo() { currentUserTimeTravelInfoThreadLocal.remove(); } /** * Public static Boolean isInTimeTravel() {return currentUserTimeTravelInfoThreadLocal.get() ! = null; } /** * gets the "current" time, in milliseconds. * If you are currently in transit, * @return */ public static long getNow() {TimeTravelInfo travelInfo = currentUserTimeTravelInfoThreadLocal.get(); return travelInfo ! = null ? travelInfo.getTravelTime() : System.currentTimeMillis(); }}Copy the code

User traversal information

/** * public class TimeTravelInfo {/** * private Boolean isInTravel = false; /** * private Long travelTime; /** private Long travelTime; public boolean isInTravel() { return isInTravel; } public void setInTravel(boolean inTravel) { isInTravel = inTravel; } public Long getTravelTime() { return travelTime; } public void setTravelTime(Long travelTime) { this.travelTime = travelTime; }}Copy the code

After the business System relies on the vivo xxx-time-travel module, change the original system.currentTimemillis () to timeTravelUtil.getNow () where the current time is needed.

3.4 the problem

An important problem encountered in the process of time machine capability building is the loss of cross-thread transmission when the openId information is passed in context.

If the underlying Java thread pool directly implements asynchronous invocation, then the context copy can be realized through the thread pool correlation interception. Our internal full-link system has been related to the thread context information through correlation proxy technology. If you’re using Hystrix for asynchronous calls, check out my other article, “How to Solve ThreadLocal Information Loss in Hystrix.”

Four, the last

The time machine related capabilities introduced in this paper are mainly applied to the official website mall, but are not limited to the e-mall scene. The time machine module is not coupled with a specific business at the time of design, so it can also be applied to some other business scenarios or have some reference significance.

Also in this paper, CLP store view focuses on the preferential price is normal, basic involved is a read operation, if some of the scenes need through to complete business function after operation, such as for actual order, then will involve some of write operations, can use at this time the shadow of the library related ability to accomplish a complete journey through operation.

Author: Wei Fuping, Development team of Vivo official website Mall