1. Upon requesting the API, the response parameters showed a total of 30 resources. The resource with id equal to 37918 was duplicated, totaling 2 instances. See Figure 1.

{
"code": 10000,
"message": "获取 CMC 用户列表成功",
"data": {
"items": [
{
"user_birthday": "1990-01-01",
"login_name": "xianwanzhou",
"add_time": "2020-03-31 09:41:07",
"user_email": "",
"group_id": "643d80843ae23bcfa95b75bae30a7656",
"id": "37918",
"user_pic": "http://uploads.cmc.lzgbdst.com/uploads/cmc_user_avatar/default_header.png",
"update_time": "2020-03-31 09:43:16",
"is_open": "1",
"user_nick": "鲜万州",
"user_mobile": "15208396209",
"user_token": "6a1de11e594d61790963eaaf1d9bee8d",
"user_chat_id": "f98e3b834f577cc3d83d74323cd3094d",
"user_type": "2",
"user_sex": "2"
},
{
"user_birthday": "1990-01-01",
"login_name": "xianwanzhou",
"add_time": "2020-03-31 09:41:07",
"user_email": "",
"group_id": "643d80843ae23bcfa95b75bae30a7656",
"id": "37918",
"user_pic": "http://uploads.cmc.lzgbdst.com/uploads/cmc_user_avatar/default_header.png",
"update_time": "2020-03-31 09:43:16",
"is_open": "1",
"user_nick": "鲜万州",
"user_mobile": "15208396209",
"user_token": "6a1de11e594d61790963eaaf1d9bee8d",
"user_chat_id": "f98e3b834f577cc3d83d74323cd3094d",
"user_type": "2",
"user_sex": "2"
}
],
"_links": {
"self": {
"href": "http://pcsapi.cmc.lzgbdst.com/v1/cmc-users?login_id=7309cba1c93fc0a80663007612b784b8&login_tid=25f49c543b8ec31c6d905def0ad99913&per-page=30&page=1"
}
},
"_meta": {
"totalCount": 30,
"pageCount": 1,
"currentPage": 1,
"perPage": 30
}
}
}
2. Checked the model class, /common/models/redis/cmc_console/User.php
<?php
namespace common\models\redis\cmc_console;
use Yii;
use common\components\redis\ActiveRecord;
/**
* This is the model class for table "{{%user}}".
*
* @property string $id
* @property string $group_id
* @property string $login_name
* @property string $user_token
* @property string $user_nick
* @property string $user_pic
* @property string $user_mobile
* @property string $user_email
* @property string $user_sex
* @property string $user_birthday
* @property string $user_type
* @property string $user_chat_id
* @property string $is_open
* @property string $add_time
* @property string $update_time
*/
class User extends ActiveRecord
{
/**
* @return array the list of attributes for this record
*/
public function attributes()
{
return ['id', 'group_id', 'login_name', 'user_token', 'user_nick', 'user_pic', 'user_mobile', 'user_email', 'user_sex', 'user_birthday', 'user_type', 'user_chat_id', 'is_open', 'add_time', 'update_time'];
}
/**
* @inheritdoc
*/
public function rules()
{
return [
[['id', 'group_id', 'login_name', 'user_token', 'user_nick', 'user_pic', 'user_mobile', 'user_email', 'user_sex', 'user_birthday', 'user_type', 'user_chat_id', 'is_open', 'add_time', 'update_time'], 'safe'],
];
}
/**
* @inheritdoc
*/
public function attributeLabels()
{
return [
'id' => Yii::t('model/redis/cmc-console/user', 'ID'),
'group_id' => Yii::t('model/redis/cmc-console/user', 'Group ID'),
'login_name' => Yii::t('model/redis/cmc-console/user', 'Login Name'),
'user_token' => Yii::t('model/redis/cmc-console/user', 'User Token'),
'user_nick' => Yii::t('model/redis/cmc-console/user', 'User Nick'),
'user_pic' => Yii::t('model/redis/cmc-console/user', 'User Pic'),
'user_mobile' => Yii::t('model/redis/cmc-console/user', 'User Mobile'),
'user_email' => Yii::t('model/redis/cmc-console/user', 'User Email'),
'user_sex' => Yii::t('model/redis/cmc-console/user', 'User Sex'),
'user_type' => Yii::t('model/redis/cmc-console/user', 'User Type'),
'user_birthday' => Yii::t('model/redis/cmc-console/user', 'User Birthday'),
'user_chat_id' => Yii::t('model/redis/cmc-console/user', 'User Chat Id'),
'is_open' => Yii::t('model/redis/cmc-console/user', 'Is Open'),
'add_time' => Yii::t('model/redis/cmc-console/user', 'Add Time'),
'update_time' => Yii::t('model/redis/cmc-console/user', 'Update Time'),
];
}
}
3. Checked /common/components/redis/ActiveRecord.php; a prefix is defined and applies to all AR keys.
<?php
/**
* Created by PhpStorm.
* User: Administrator
* Date: 2018/02/05
* Time: 9:47
*/
namespace common\components\redis;
use Yii;
class ActiveRecord extends \yii\redis\ActiveRecord
{
/**
* Declares prefix of the key that represents the keys that store this records in redis.
* By default this method returns the class name as the table name by calling [[Inflector::camel2id()]].
* For example, 'Customer' becomes 'customer', and 'OrderItem' becomes
* 'order_item'. You may override this method if you want different key naming.
* @return string the prefix to apply to all AR keys
*/
public static function keyPrefix()
{
return Yii::$app->params['redisActiveRecord']['keyPrefix'] . parent::keyPrefix();
}
}
4. Opened RedisDesktopManager and checked the total number of users, which was confirmed to be 29. See Figure 2.

5. Opened RedisDesktopManager and confirmed there was only 1 record with the primary key value 37918, meaning it was not duplicated. See Figure 3.

6. Checked the value of pa:ar:user and found that the values of rows 29 and 30 were both 37918. This confirmed that the value of this key caused the resource count for id 37918 to equal 2. See Figure 4.

7. Deleted row 30 of pa:ar:user. See Figure 5.

8. Requested the API again, and the response parameters showed a total of 29 resources. The resource with id equal to 37918 was no longer duplicated, leaving only 1 instance.
{
"code": 10000,
"message": "获取 CMC 用户列表成功",
"data": {
"items": [
{
"user_birthday": "1990-01-01",
"login_name": "xianwanzhou",
"add_time": "2020-03-31 09:41:07",
"user_email": "",
"group_id": "643d80843ae23bcfa95b75bae30a7656",
"id": "37918",
"user_pic": "http://uploads.cmc.lzgbdst.com/uploads/cmc_user_avatar/default_header.png",
"update_time": "2020-03-31 09:43:16",
"is_open": "1",
"user_nick": "鲜万州",
"user_mobile": "15208396209",
"user_token": "6a1de11e594d61790963eaaf1d9bee8d",
"user_chat_id": "f98e3b834f577cc3d83d74323cd3094d",
"user_type": "2",
"user_sex": "2"
}
],
"_links": {
"self": {
"href": "http://pcsapi.cmc.lzgbdst.com/v1/cmc-users?login_id=7309cba1c93fc0a80663007612b784b8&login_tid=25f49c543b8ec31c6d905def0ad99913&per-page=29&page=1"
}
},
"_meta": {
"totalCount": 29,
"pageCount": 1,
"currentPage": 1,
"perPage": 29
}
}
}
9. Prepared to reproduce the duplicate primary key ID issue in the local environment. Requested the API, and the response parameters showed a total of 13 resources. The primary key ID was not duplicated. See Figure 6.

{
"code": 10000,
"message": "获取 CMC 用户列表成功",
"data": {
"items": [
{
"login_name": "13281105967",
"update_time": "2019-12-11 14:28:26",
"group_id": "015ce30b116ce86058fa6ab4fea4ac63",
"user_nick": "13281105967",
"user_sex": "2",
"user_mobile": "13281105967",
"user_type": "1",
"is_open": "1",
"user_chat_id": "ede7616c5e4232896453202cd0c3f7ec",
"user_pic": "https://pgcupload.flydev.chinamcloud.cn/uploads/cmc_user_avatar/20190219/1550570817-4LLQJJ.png",
"id": "3",
"add_time": "2018-04-26 10:05:28",
"user_birthday": "1990-01-01",
"user_email": "13281105967@chinamcloud.com",
"user_token": "fb46626f0e71e423ca8ab4c750620a85"
},
{
"login_name": "test10",
"update_time": "2019-12-11 15:00:38",
"group_id": "015ce30b116ce86058fa6ab4fea4ac63",
"user_nick": "test10",
"user_sex": "2",
"user_mobile": "13980074657",
"user_type": "2",
"is_open": "1",
"user_chat_id": "ce524778954bd10d5a0ff65dadc0354b",
"user_pic": "https://pgcupload.flydev.chinamcloud.cn/uploads/cmc_user_avatar/default_header.png",
"id": "4",
"add_time": "2019-12-11 14:55:07",
"user_birthday": "1990-01-01",
"user_email": "",
"user_token": "bc8daab7ba8620c132cdf4e5de1d4758"
},
{
"login_name": "jmj12130003",
"update_time": "2019-12-13 14:41:55",
"group_id": "015ce30b116ce86058fa6ab4fea4ac63",
"user_nick": "jmj1213",
"user_sex": "2",
"user_mobile": "18412130003",
"user_type": "2",
"is_open": "1",
"user_chat_id": "84e1bb32ffa895e56d950bbfa24fefc7",
"user_pic": "https://pgcupload.flydev.chinamcloud.cn/uploads/cmc_user_avatar/default_header.png",
"id": "49",
"add_time": "2019-12-13 14:41:55",
"user_birthday": "1990-01-01",
"user_email": "",
"user_token": "ba0ca65da7c3048fd9d449bb0d21a39b"
},
{
"login_name": "test11",
"update_time": "2019-12-17 11:14:53",
"group_id": "015ce30b116ce86058fa6ab4fea4ac63",
"user_nick": "test11",
"user_sex": "2",
"user_mobile": "13980074650",
"user_type": "2",
"is_open": "1",
"user_chat_id": "bc1650a6834fc490de65a4527dfc8ae5",
"user_pic": "https://pgcupload.flydev.chinamcloud.cn/uploads/cmc_user_avatar/default_header.png",
"id": "64",
"add_time": "2019-12-17 11:14:53",
"user_birthday": "1990-01-01",
"user_email": "",
"user_token": "04532bb62deb99bf229698c9e1a81da1"
},
{
"login_name": "test12",
"update_time": "2019-12-17 11:15:14",
"group_id": "015ce30b116ce86058fa6ab4fea4ac63",
"user_nick": "test12",
"user_sex": "2",
"user_mobile": "13980074651",
"user_type": "2",
"is_open": "1",
"user_chat_id": "fa154673421e5a3731991498397d712d",
"user_pic": "https://pgcupload.flydev.chinamcloud.cn/uploads/cmc_user_avatar/default_header.png",
"id": "65",
"add_time": "2019-12-17 11:15:14",
"user_birthday": "1990-01-01",
"user_email": "",
"user_token": "bcdc9e3781180b7bc18bc0e38777a467"
},
{
"login_name": "test13",
"update_time": "2019-12-17 11:15:35",
"group_id": "015ce30b116ce86058fa6ab4fea4ac63",
"user_nick": "test13",
"user_sex": "2",
"user_mobile": "13980074652",
"user_type": "2",
"is_open": "1",
"user_chat_id": "35ce7075c1c57bb6c66d0f67a7840383",
"user_pic": "https://pgcupload.flydev.chinamcloud.cn/uploads/cmc_user_avatar/default_header.png",
"id": "66",
"add_time": "2019-12-17 11:15:35",
"user_birthday": "1990-01-01",
"user_email": "",
"user_token": "633cae769e274cabd4441acb7be1c5a1"
},
{
"login_name": "test14",
"update_time": "2019-12-17 11:15:55",
"group_id": "015ce30b116ce86058fa6ab4fea4ac63",
"user_nick": "test14",
"user_sex": "2",
"user_mobile": "13980074654",
"user_type": "2",
"is_open": "1",
"user_chat_id": "3190c55b297b51b38463da4eae6bbd95",
"user_pic": "https://pgcupload.flydev.chinamcloud.cn/uploads/cmc_user_avatar/default_header.png",
"id": "67",
"add_time": "2019-12-17 11:15:55",
"user_birthday": "1990-01-01",
"user_email": "",
"user_token": "84c5871da19f7a489234af73c491f74f"
},
{
"login_name": "test15",
"update_time": "2019-12-17 11:16:16",
"group_id": "015ce30b116ce86058fa6ab4fea4ac63",
"user_nick": "test15",
"user_sex": "2",
"user_mobile": "13980074655",
"user_type": "2",
"is_open": "1",
"user_chat_id": "fd072f598ec1a978f5fb968dfa386f0d",
"user_pic": "https://pgcupload.flydev.chinamcloud.cn/uploads/cmc_user_avatar/default_header.png",
"id": "68",
"add_time": "2019-12-17 11:16:16",
"user_birthday": "1990-01-01",
"user_email": "",
"user_token": "5bb37b4045e9ad6eb1cc398d3170d33e"
},
{
"login_name": "test16",
"update_time": "2019-12-17 11:16:36",
"group_id": "015ce30b116ce86058fa6ab4fea4ac63",
"user_nick": "test16",
"user_sex": "2",
"user_mobile": "13980074656",
"user_type": "2",
"is_open": "1",
"user_chat_id": "88178648656ae259bae213ee00ccb4c7",
"user_pic": "https://pgcupload.flydev.chinamcloud.cn/uploads/cmc_user_avatar/default_header.png",
"id": "69",
"add_time": "2019-12-17 11:16:36",
"user_birthday": "1990-01-01",
"user_email": "",
"user_token": "2926796eb8e990aa8bd726e121cb91e8"
},
{
"login_name": "test17",
"update_time": "2019-12-17 11:17:07",
"group_id": "015ce30b116ce86058fa6ab4fea4ac63",
"user_nick": "test17",
"user_sex": "2",
"user_mobile": "13980074653",
"user_type": "2",
"is_open": "1",
"user_chat_id": "b03d6e7b4db061d52b3d420844a5dde8",
"user_pic": "https://pgcupload.flydev.chinamcloud.cn/uploads/cmc_user_avatar/default_header.png",
"id": "70",
"add_time": "2019-12-17 11:17:07",
"user_birthday": "1990-01-01",
"user_email": "",
"user_token": "bf028bc0353bf8ff070bfd62490ae284"
},
{
"login_name": "test18",
"update_time": "2019-12-17 11:17:25",
"group_id": "015ce30b116ce86058fa6ab4fea4ac63",
"user_nick": "test18",
"user_sex": "2",
"user_mobile": "13980074658",
"user_type": "2",
"is_open": "1",
"user_chat_id": "c1eddd55f8efcec8da1e0cc6fc1a5624",
"user_pic": "https://pgcupload.flydev.chinamcloud.cn/uploads/cmc_user_avatar/default_header.png",
"id": "71",
"add_time": "2019-12-17 11:17:25",
"user_birthday": "1990-01-01",
"user_email": "",
"user_token": "4adbe2313b7e4967ac518e4e0a73f5c9"
},
{
"login_name": "test19",
"update_time": "2019-12-17 11:17:41",
"group_id": "015ce30b116ce86058fa6ab4fea4ac63",
"user_nick": "test19",
"user_sex": "2",
"user_mobile": "13980074659",
"user_type": "2",
"is_open": "1",
"user_chat_id": "5bf1e9f7e4bf9aa2d8a633eddf628710",
"user_pic": "https://pgcupload.flydev.chinamcloud.cn/uploads/cmc_user_avatar/default_header.png",
"id": "72",
"add_time": "2019-12-17 11:17:41",
"user_birthday": "1990-01-01",
"user_email": "",
"user_token": "dd7ab3f1fb3e8651b35ba070d10594c7"
},
{
"login_name": "15708495493",
"update_time": "2020-03-02 14:31:36",
"group_id": "015ce30b116ce86058fa6ab4fea4ac63",
"user_nick": "clover",
"user_sex": "2",
"user_mobile": "15708495493",
"user_type": "2",
"is_open": "1",
"user_chat_id": "251f91338781d5354e08c1351ca3342d",
"user_pic": "https://pgcupload.flydev.chinamcloud.cn/uploads/cmc_user_avatar/default_header.png",
"id": "166",
"add_time": "2020-03-02 14:31:36",
"user_birthday": "1990-01-01",
"user_email": "",
"user_token": "ff94d3f7b1dafada193ae7d6a82fa628"
}
],
"_links": {
"self": {
"href": "http://api.pcs-api.localhost/v1/cmc-users?login_id=2e368664c41b8bf511bcc9c65d86dbc3&login_tid=efda7e64b7747f8c4360b29aa9c18f77&per-page=13&page=1"
}
},
"_meta": {
"totalCount": 13,
"pageCount": 1,
"currentPage": 1,
"perPage": 13
}
}
}
10. During program execution, when inserting data into Redis, it checks whether the ID already exists: if it exists, it updates; if not, it inserts. I initially suspected that under concurrent requests, all operations executed the insert.
$redisCmcConsoleUser = new RedisCmcConsoleUser();
$redisCmcConsoleUserResult = $redisCmcConsoleUser->initSync(['group_id' => $groupInfo['group_id']], $loginId, $loginTid);
if ($redisCmcConsoleUserResult === false) {
throw new NotFoundHttpException(Yii::t('error', Yii::t('error', Yii::t('error', '201041'), ['id' => $loginId])), 201041);
}
$redisCmcConsoleUserItem = $redisCmcConsoleUser::find()->where(['id' => $userInfo['id'], 'group_id' => Yii::$app->params['groupId']])->one();
/* 如果资源不存在,则插入;否则更新 */
$redisCmcConsoleUserAttributes = [
'id' => $userInfo['id'],
'group_id' => $groupInfo['group_id'],
'login_name' => $userInfo['login_name'],
'user_token' => $userInfo['user_token'],
'user_nick' => $userInfo['user_nick'],
'user_pic' => $userInfo['user_pic'],
'user_mobile' => $userInfo['user_mobile'] ? $userInfo['user_mobile'] : '',
'user_email' => $userInfo['user_email'] ? $userInfo['user_email'] : '',
'user_sex' => $userInfo['user_sex'],
'user_type' => $userInfo['user_type'],
'user_birthday' => $userInfo['user_birthday'],
'user_chat_id' => $userInfo['user_chat_id'] ? $userInfo['user_chat_id'] : '',
'is_open' => $userInfo['is_open'],
'add_time' => $userInfo['add_time'],
'update_time' => $userInfo['update_time'],
];
if (!isset($redisCmcConsoleUserItem)) {
$redisCmcConsoleUser->attributes = $redisCmcConsoleUserAttributes;
$redisCmcConsoleUser->insert();
// 设置用户身份为已认证
Yii::$app->user->setIdentity($redisCmcConsoleUser);
} else {
$redisCmcConsoleUserItem->attributes = $redisCmcConsoleUserAttributes;
$redisCmcConsoleUserItem->save();
// 设置用户身份为已认证
Yii::$app->user->setIdentity($redisCmcConsoleUserItem);
}
11. During program execution, when inserting data into Redis, it inserts regardless of whether the ID exists. Requested the API, and the response parameters showed a total of 14 resources. The resource with id equal to 3 was duplicated, totaling 2 instances. See Figure 7.

if (!isset($redisCmcConsoleUserItem)) {
$redisCmcConsoleUser->attributes = $redisCmcConsoleUserAttributes;
$redisCmcConsoleUser->insert();
// 设置用户身份为已认证
Yii::$app->user->setIdentity($redisCmcConsoleUser);
} else {
$redisCmcConsoleUserItem->attributes = $redisCmcConsoleUserAttributes;
$redisCmcConsoleUserItem->insert();
// 设置用户身份为已认证
Yii::$app->user->setIdentity($redisCmcConsoleUserItem);
}
{
"code": 10000,
"message": "获取 CMC 用户列表成功",
"data": {
"items": [
{
"login_name": "13281105967",
"update_time": "2019-12-11 14:28:26",
"group_id": "015ce30b116ce86058fa6ab4fea4ac63",
"user_nick": "13281105967",
"user_sex": "2",
"user_mobile": "13281105967",
"user_type": "1",
"is_open": "1",
"user_chat_id": "ede7616c5e4232896453202cd0c3f7ec",
"user_pic": "https://pgcupload.flydev.chinamcloud.cn/uploads/cmc_user_avatar/20190219/1550570817-4LLQJJ.png",
"id": "3",
"add_time": "2018-04-26 10:05:28",
"user_birthday": "1990-01-01",
"user_email": "13281105967@chinamcloud.com",
"user_token": "fb46626f0e71e423ca8ab4c750620a85"
},
{
"login_name": "13281105967",
"update_time": "2019-12-11 14:28:26",
"group_id": "015ce30b116ce86058fa6ab4fea4ac63",
"user_nick": "13281105967",
"user_sex": "2",
"user_mobile": "13281105967",
"user_type": "1",
"is_open": "1",
"user_chat_id": "ede7616c5e4232896453202cd0c3f7ec",
"user_pic": "https://pgcupload.flydev.chinamcloud.cn/uploads/cmc_user_avatar/20190219/1550570817-4LLQJJ.png",
"id": "3",
"add_time": "2018-04-26 10:05:28",
"user_birthday": "1990-01-01",
"user_email": "13281105967@chinamcloud.com",
"user_token": "fb46626f0e71e423ca8ab4c750620a85"
}
],
"_links": {
"self": {
"href": "http://api.pcs-api.localhost/v1/cmc-users?login_id=2e368664c41b8bf511bcc9c65d86dbc3&login_tid=efda7e64b7747f8c4360b29aa9c18f77&per-page=14&page=1"
}
},
"_meta": {
"totalCount": 14,
"pageCount": 1,
"currentPage": 1,
"perPage": 14
}
}
}
12. This confirms that Redis ActiveRecord cannot ensure the uniqueness of the primary key ID. At present, there are two solutions. The first solution is to implement a uniqueness lock based on Redis when inserting records. The second solution is to deduplicate during the query. I decided to adopt the second solution. Since Redis does not support SQL queries, the query API is limited to the following methods: where(), limit(), offset(), orderBy(), and indexBy(). (orderBy() is not yet implemented: #1305). Based on indexBy(). Requested the API, and the response parameters showed a total of 13 resources. The primary key ID was not duplicated. However, the value of totalCount was 14. The count was incorrect. See Figure 8.

// 查询当前用户所属租户 ID 下的 CMC 的用户模型(Redis)
$query = $modelClass::find()
->where([
'group_id' => $identity->group_id,
'is_open' => $modelClass::STATUS_ENABLED
])
->indexBy('id');
{
"code": 10000,
"message": "获取 CMC 用户列表成功",
"data": {
"items": [
{
"login_name": "13281105967",
"update_time": "2019-12-11 14:28:26",
"group_id": "015ce30b116ce86058fa6ab4fea4ac63",
"user_nick": "13281105967",
"user_sex": "2",
"user_mobile": "13281105967",
"user_type": "1",
"is_open": "1",
"user_chat_id": "ede7616c5e4232896453202cd0c3f7ec",
"user_pic": "https://pgcupload.flydev.chinamcloud.cn/uploads/cmc_user_avatar/20190219/1550570817-4LLQJJ.png",
"id": "3",
"add_time": "2018-04-26 10:05:28",
"user_birthday": "1990-01-01",
"user_email": "13281105967@chinamcloud.com",
"user_token": "fb46626f0e71e423ca8ab4c750620a85"
}
],
"_links": {
"self": {
"href": "http://api.pcs-api.localhost/v1/cmc-users?login_id=2e368664c41b8bf511bcc9c65d86dbc3&login_tid=efda7e64b7747f8c4360b29aa9c18f77&per-page=14&page=1"
}
},
"_meta": {
"totalCount": 14,
"pageCount": 1,
"currentPage": 1,
"perPage": 14
}
}
}
13. Therefore, I tried adopting the first solution. However, since the program implementation here is a flow executed by all requests, I was concerned that implementing locking would degrade program performance. Ultimately, I decided to abandon insertion and only perform updates. The original logic was: if the user does not exist in Redis, insert; otherwise, update. This was adjusted to: if the user does not exist in Redis, respond with 404; otherwise, update.
/* 如果资源不存在,则响应 404 */
if (!isset($redisCmcConsoleUserItem)) {
throw new NotFoundHttpException(Yii::t('error', Yii::t('error', Yii::t('error', '201011'), ['user_nick' => $userInfo['user_nick']])), 201011);
}
/* 更新 */
$redisCmcConsoleUserItem->attributes = $redisCmcConsoleUserAttributes;
$redisCmcConsoleUserItem->save();
// 设置用户身份为已认证
Yii::$app->user->setIdentity($redisCmcConsoleUserItem);
14. If the user does not exist in Redis, respond with 404. See Figure 9.

15. However, this fix only prevents user duplication issues from occurring in the future; previously duplicated users remain duplicated. To deduplicate them, manual operations on Redis are required. Moreover, this fix introduces a new issue affecting the user experience: after adding a new user B in the framework, if user B does not exist in Redis, user B cannot use the planning command. User B can only use it after waiting for the user to be synchronized to Redis.
