Timer Programming Sharing
Timer Program Design Sharing
1. Background
The timer program referred to in this paper is not a narrow timer program, but a general way to achieve certain business scenarios through the timer trigger program, combined with the database.
2. Scheme Analysis
3.1 Scene 1
3.1.1 Requirements
We need to push completed order data to third-party systems.
3.1.2 SQL
DROP TABLE IF EXISTS order01; CREATE TABLE order01 ( order_id BIGINT UNSIGNED NOT NULL COMMENT 'Order ID', order_desc VARCHAR(256) NOT NULL DEFAULT '' COMMENT 'Order Description', order_state TINYINT UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Order Status[0:initial, 10:Paid, ... 100:Completed]', order_push_state TINYINT UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Order Push Status[0:initial, 100:Push Success]', create_time DATETIME NOT NULL COMMENT 'Creation Time', update_time DATETIME NULL COMMENT 'Modification Time', PRIMARY KEY (order_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Order form (example 01)';
3.1.3 Services
SQL Service
<!-- Get a push order --> <selectOne id="getOrder01" dsKey="timerReadDB" txRef="tx_01"> select * from order01 where order_state = 100 AND order_push_state = 0 LIMIT 1 </selectOne> <!-- Complete a push for an order --> <update id="completePushOrder01" dsKey="timerWriteDB" txRef="tx_02"> update order01 set order_push_state = 100, update_time = #{push_update_time|now()} where order_id = #{order_id} AND order_push_state = 0 </update>
JAVA Service
/** * Scheme 3.1 Related Push Service Entry */ public void pushOrder01(XCO request) { // 1. Get an order to push XCO getRes = ServiceActuator.executeAlone("timer/getOrder01", new XCO()); if (0 != getRes.getCode()) { log.error("Get an order exception to push: " + getRes.getMessage()); return; } XCO order = getRes.getData(); if (null == order) { return;// No pending orders } // 2. Push to third parties ServiceActuator.executeAlone("timerService/receiveOrder", order); // 3. Mark that this order has been pushed ServiceActuator.executeAlone("timer/completePushOrder01", order); }
3.1.4 Timer
<!-- Option 3.1 Relevant Timer --> <timer scheduled="/10 * * * * ?" service="timerService/pushOrder01" desc="Push Order (Option 3).1)" sync="true"/>
3.2 Scene 2
3.2.1 Requirements
We need to push the completed order data to a third-party system. If the push fails, the order will need to be delayed for 10 minutes before the next push can be initiated.
3.2.2 SQL
DROP TABLE IF EXISTS order02; CREATE TABLE order02 ( order_id BIGINT UNSIGNED NOT NULL COMMENT 'Order ID', order_desc VARCHAR(256) NOT NULL DEFAULT '' COMMENT 'Order Description', order_state TINYINT UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Order Status[0:initial, 10:Paid, ... 100:Completed]', order_push_state TINYINT UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Order Push Status[0:initial, 90:Push failed, 100:Push Success]', scheduled_push_time DATETIME NOT NULL COMMENT 'Schedule Push Time', create_time DATETIME NOT NULL COMMENT 'Creation Time', update_time DATETIME NULL COMMENT 'Modification Time', PRIMARY KEY (order_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Order form (example 02)';
3.2.3 Services
SQL Service
<selectOne id="getOrder02" dsKey="timerReadDB" txRef="tx_01"><![CDATA[ select * from order02 where order_state = 100 AND order_push_state = 0 AND #{current_push_time|now()} >= scheduled_push_time LIMIT 1 ]]></selectOne> <update id="completePushOrder02" dsKey="timerWriteDB" txRef="tx_02"> <if test="{flag} == 0"> update order02 set order_push_state = 100, update_time = #{time|now()} where order_id = #{order_id} AND order_push_state = 0 </if> <else> update order02 set scheduled_push_time = #{scheduled_push_time}, update_time = #{time|now()} where order_id = #{order_id} AND order_push_state = 0 </else> </update>
JAVA Service
/** * Option 3.2 related push service entry, if the push fails, the order will need to be delayed for 10 minutes before the next push can be initiated. */ public void pushOrder02(XCO request) { // 1. Get an order to push XCO getRes = ServiceActuator.executeAlone("timer/getOrder02", new XCO()); if (0 != getRes.getCode()) { log.error("Get an order exception to push: " + getRes.getMessage()); return; } XCO order = getRes.getData(); if (null == order) { return;// No pending orders } // 2. Push to third parties XCO receiveRes = ServiceActuator.executeAlone("timerService/receiveOrder", order); int flag = 0; if (0 != receiveRes.getCode()) { // Push failed Date scheduled_push_time = order.getDateTimeValue("scheduled_push_time"); // Add 10 minutes scheduled_push_time.setTime(scheduled_push_time.getTime() + 10L * 60L * 1000L); flag = 1; } order.setIntegerValue("flag", flag); // 3. Mark that this order has been pushed ServiceActuator.executeAlone("timer/completePushOrder02", order); }
3.2.4 Timer
<!-- Option 3.2 Relevant Timer --> <timer scheduled="/10 * * * * ?" service="timerService/pushOrder02" desc="Push Order (Option 3).2)" sync="true"/>
3.3 Scene 3
3.3.1 Requirements
We need to push the completed order data to a third-party system. If the push fails, the order will need to be delayed for 10 minutes before the next push can be initiated and up to three attempts can be made.
3.3.2 SQL
DROP TABLE IF EXISTS order03; CREATE TABLE order03 ( order_id BIGINT UNSIGNED NOT NULL COMMENT 'Order ID', order_desc VARCHAR(256) NOT NULL DEFAULT '' COMMENT 'Order Description', order_state TINYINT UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Order Status[0:initial, 10:Paid, ... 100:Completed]', order_push_state TINYINT UNSIGNED NOT NULL DEFAULT 0 COMMENT 'Order Push Status[0:initial, 90:Push failed, 100:Push Success]', retry_count BIGINT UNSIGNED NOT NULL DEFAULT 0 COMMENT 'retry count', scheduled_push_time DATETIME NOT NULL COMMENT 'Schedule Push Time', create_time DATETIME NOT NULL COMMENT 'Creation Time', update_time DATETIME NULL COMMENT 'Modification Time', PRIMARY KEY (order_id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Order form (example 03)';
3.3.3 Services
SQL Service
<selectOne id="getOrder03" dsKey="timerReadDB" txRef="tx_01"><![CDATA[ select * from order03 where order_state = 100 AND order_push_state = 0 AND #{current_push_time|now()} >= scheduled_push_time LIMIT 1 ]]></selectOne> <update id="completePushOrder03" dsKey="timerWriteDB" txRef="tx_02"> <if test="{flag} == 0"> update order03 set order_push_state = 100, update_time = #{time|now()} where order_id = #{order_id} AND order_push_state = 0 </if> <elseif test="{flag} == 1"> update order03 set retry_count = retry_count + 1, scheduled_push_time = #{scheduled_push_time}, update_time = #{time|now()} where order_id = #{order_id} AND order_push_state = 0 </elseif> <else> update order03 set order_push_state = 90, update_time = #{time|now()} where order_id = #{order_id} AND order_push_state = 0 </else> </update>
JAVA Service
/** * Option 3.2 related push service entry, if the push fails, the order will need to be delayed for 10 minutes before the next push can be initiated and up to three attempts can be made. */ public void pushOrder03(XCO request) { // 1. Get an order to push XCO getRes = ServiceActuator.executeAlone("timer/getOrder03", new XCO()); if (0 != getRes.getCode()) { log.error("Get an order exception to push: " + getRes.getMessage()); return; } XCO order = getRes.getData(); if (null == order) { return;// No pending orders } // 2. Push to third parties XCO receiveRes = ServiceActuator.executeAlone("timerService/receiveOrder", order); int flag = 0; if (0 != receiveRes.getCode()) { // Push failed Date scheduled_push_time = order.getDateTimeValue("scheduled_push_time"); // Add 10 minutes scheduled_push_time.setTime(scheduled_push_time.getTime() + 10L * 60L * 1000L); flag = 1; // Number of attempts interpretation if (receiveRes.getIntegerValue("retry_count") > 2) { flag = 2; } } order.setIntegerValue("flag", flag); // 3. Mark that this order has been pushed ServiceActuator.executeAlone("timer/completePushOrder02", order); }
3.3.4 Timer
<!-- Option 3.3 Relevant Timer --> <timer scheduled="/10 * * * * ?" service="timerService/pushOrder03" desc="Push Order (Option 3).3)" sync="true"/>
3.4 Technical optimization scheme 1 for 3.1
3.4.1 Requirements
Requirements same as 3.1.1, Technical optimization point: Get multiple tasks at once
3.4.2 SQL
Same as 3.1.2
3.4.3 Services
SQL Service
<selectSet id="getOrderList01" dsKey="timerReadDB" txRef="tx_01"> select * from order01 where order_state = 100 AND order_push_state = 0 LIMIT 100 </selectSet>
JAVA Service
/** * Scenario 3.4 Related Push Service Entry, Get Multiple Tasks at a Time */ public void pushOrder04(XCO request) { // 1. Get multiple pending orders XCO getRes = ServiceActuator.executeAlone("timer/getOrderList01", new XCO()); if (0 != getRes.getCode()) { log.error("Get multiple push order exceptions: " + getRes.getMessage()); return; } List<XCO> orders = getRes.getData(); if (CollectionUtils.isEmpty(orders)) { return;// No pending orders } for (XCO order : orders) { // 2. Push to third parties ServiceActuator.executeAlone("timerService/receiveOrder", order); // 3. Mark that this order has been pushed ServiceActuator.executeAlone("timer/completePushOrder01", order); } }
3.4.4 Timer
<!-- Option 3.4 Relevant Timer --> <timer scheduled="/10 * * * * ?" service="timerService/pushOrder04" desc="Push Order (Option 3).4)" sync="true"/>
3.5 Technical optimization scheme for 3.1 2
3.5.1 Requirements
Requirements same as 3.1.1, Technical optimization point: Get multiple tasks at once and support multiple Timer s at the same time
3.5.2 SQL
Same as 3.1.2
3.5.3 Services
SQL Service
<selectSet id="getOrderList02" dsKey="timerReadDB" txRef="tx_01"> select * from order01 where order_state = 100 AND order_push_state = 0 AND (order_id % #{tt_total} = #{tt_index}) LIMIT 100 </selectSet>
JAVA Service
/** * Scenario 3.5 related push service entry, get multiple tasks at a time, and support multiple Timer s at the same time */ public void pushOrder05(XCO request) { // 1. Get multiple pending orders XCO getRes = ServiceActuator.executeAlone("timer/getOrderList02", request); if (0 != getRes.getCode()) { log.error("Get multiple push order exceptions: " + getRes.getMessage()); return; } List<XCO> orders = getRes.getData(); if (CollectionUtils.isEmpty(orders)) { return;// No pending orders } for (XCO order : orders) { // 2. Push to third parties ServiceActuator.executeAlone("timerService/receiveOrder", order); // 3. Mark that this order has been pushed ServiceActuator.executeAlone("timer/completePushOrder01", order); } }
3.5.4 Timer
<!-- Option 3.5 Relevant Timer --> <timer scheduled="/10 * * * * ?" service="timerService/pushOrder05" desc="Push Order (Option 3).5)[0]" sync="true"> <property name="tt_index" value="0"/> <property name="tt_total" value="5"/> </timer> <timer scheduled="/10 * * * * ?" service="timerService/pushOrder05" desc="Push Order (Option 3).5)[1]" sync="true"> <property name="tt_index" value="1"/> <property name="tt_total" value="5"/> </timer> <timer scheduled="/10 * * * * ?" service="timerService/pushOrder05" desc="Push Order (Option 3).5)[2]" sync="true"> <property name="tt_index" value="2"/> <property name="tt_total" value="5"/> </timer> <timer scheduled="/10 * * * * ?" service="timerService/pushOrder05" desc="Push Order (Option 3).5)[3]" sync="true"> <property name="tt_index" value="3"/> <property name="tt_total" value="5"/> </timer> <timer scheduled="/10 * * * * ?" service="timerService/pushOrder05" desc="Push Order (Option 3).5)[4]" sync="true"> <property name="tt_index" value="4"/> <property name="tt_total" value="5"/> </timer>
3. Program Summary
SN | Scenario Name | describe |
---|---|---|
1 | Scenario One | Simple, regardless of failure |
2 | Scenario Two | Increase support for deferred push after failure |
3 | Scene Three | Increase maximum number of attempts after failure control |
4 | Scene 1 Optimization | Get more than one push task at a time |
5 | Scene 1 Optimization | Support multiple Timer s for parallel processing at the same time |
In the actual development process, we should choose the appropriate implementation according to the specific business scenario and needs.