Business logic: users vote, and records are written after voting; after successful voting, the user status is changed and no more votes are allowed.
it"s OK to pass the postman test interface directly, and the data is normal. However, as long as the test is run through a multi-process script, the number of records written will increase.
solution that comes to mind at present:
- use redis to order collections, use timestamp millisecond writes to get the first one, and then compare it. To put it simply, it is to do concurrency processing in the millisecond dimension, but it feels that if the concurrency is higher, it should also be a problem.
- is processed using the queue service.
Voting Code:
$uid = Token::getCurrentUid();
$codeNum = Token::getCurrentTokenVar("codeNum");
//
$redis = Redis::getRedisConn();
$key = RedisKeyNameLibrary::USER_VOTE.$codeNum;
$score = array_sum(explode(" ", microtime()));
$value = build_rand_str(32).":".$uid;
$redis->zRemRangeByScore($key, 0, time() - 1);//1
$redis->zAdd($key, $score, $value);
$zRangeArr = $redis->zRange($key, 0, -1);
if ($zRangeArr[0] <> $value) return returnError("", 30002);
$tran = $this->db();
$tran->startTrans();
try{
//ID
$model = self::get($uid);
$data = array_merge($model->toArray(), $data);
//
$validate = new CodeValidate();
$result = $validate->check($data, [], "vote");
if(!$result) return returnError($validate->getError(), 30001);
$errorMsg = returnError("", 30002);
//
$status = $model->data($data)->allowField(true)->save(["status" => self::STATUS_1]);
//
if($status !== false) {
$saveData = [];
$models = User::all(array_map("intval", $data["user_ids"]))->all();
foreach($models as $k => $v) array_push($saveData, [
"code_num" => $data["code_num"], "uid" => $v->data["id"],
"name" => $v->data["name"], "group_id" => $v->data["group_id"]
]);
$model->logs()->saveAll($saveData);
$tran->commit();
return returnSuccess();
}
return $errorMsg;
}catch (Exception $e){
$tran->rollback();
return $errorMsg;
}
the following is a script for multiple processes to test the voting interface:
for ($i = 0; $i < 6; $i PP) {
$pid = pcntl_fork();
if ($pid == - 1) {
die("could not fork");
} elseif ($pid) {
echo "I"m the Parent $i\n";
} else {
$token = "123123";
$url = "http://api.com/user";
$query = "user_ids[]=1&user_ids[]=39&user_ids[]=19&user_ids[]=30";
$command = "curl -H "token:" . $token . "" -X POST -d "" . $query . "" " . $url;
//
$res = system($command);
file_put_contents($i . "_work.log", var_export($res, true));
exit(); // ,pcntl_fork() fork,
}
}
//
while (pcntl_waitpid(0, $status) != - 1) {
$status = pcntl_wexitstatus($status);
echo "Child $status completed\n";
}
I would like to ask, is there any other solution besides the above solution? (it"s better not to start other services, etc.)