SettlementTraffic.php 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. <?php
  2. namespace app\common\command;
  3. use app\common\model\FlowLogs;
  4. use app\common\model\User;
  5. use app\common\model\UserTraffic;
  6. use think\console\Command;
  7. use think\console\Input;
  8. use think\console\Output;
  9. use think\Db;
  10. use think\Exception;
  11. class SettlementTraffic extends Command
  12. {
  13. protected function configure()
  14. {
  15. // parent::configure(); // TODO: Change the autogenerated stub
  16. $this->setName('settlement')->setDescription('后台统计用户流量使用, 并扣除相关流量');
  17. }
  18. /**
  19. * 功能: 执行任务, 计算统计使用的流量
  20. * @param Input $input
  21. * @param Output $output
  22. * @return int|void|null
  23. * @throws \think\db\exception\DataNotFoundException
  24. * @throws \think\db\exception\ModelNotFoundException
  25. * @throws \think\exception\DbException
  26. */
  27. protected function execute(Input $input, Output $output)
  28. {
  29. // parent::execute($input, $output); // TODO: Change the autogenerated stub
  30. // $output->writeln("TestCommand");
  31. $dateTime = time() - 5; // 设置处理数据的时间为当前时间的前5秒,避免数据竞争
  32. // 分组统计出指定时间内用户使用了的流量
  33. $data = FlowLogs::where('created_at', '<=', $dateTime)
  34. ->field('username, sum(bytes) as bytes')
  35. ->group('username')
  36. ->select()->toArray();
  37. // 当前数据所有用户名的数组
  38. $userNames = array_column($data, 'username');
  39. $users = collection(User::whereIn('username', $userNames)->field('id, username')->select())->toArray();
  40. $userNameMapId = array_column($users, 'id', 'username');
  41. Db::startTrans();
  42. try {
  43. foreach ($data as $datum) {
  44. if (!$this->usedTraffic($userNameMapId[$datum['username']], $datum['bytes'], $dateTime)) {
  45. throw new Exception('统计用户使用流量失败');
  46. }
  47. }
  48. // 指定时间段的流量已统计,删除相关记录
  49. FlowLogs::where('created_at', '<=', $dateTime)->delete();
  50. // 统计数据成功,提交事物
  51. Db::commit();
  52. } catch (Exception $e) { // 操作失败,数据库信息回滚
  53. Db::rollback();
  54. }
  55. }
  56. /**
  57. * 功能: 处理用户使用过的流量
  58. * @param $uid
  59. * @param $bytes
  60. * @param $dateTime
  61. * @return bool
  62. * @throws \think\db\exception\DataNotFoundException
  63. * @throws \think\db\exception\ModelNotFoundException
  64. * @throws \think\exception\DbException
  65. */
  66. protected function usedTraffic($uid, $bytes, $dateTime)
  67. {
  68. $usable = UserTraffic::where('uid', $uid)
  69. ->where('is_usable', '1')
  70. ->where('start_time', '<', $dateTime)
  71. ->where('expired_time', '>', $dateTime)
  72. ->order('expired_time', 'ASC')
  73. ->select();
  74. if (empty($usable)) {
  75. return true;
  76. }
  77. foreach ($usable as $item) {
  78. if ($bytes == 0) break;
  79. if ($item->traffic > bcadd($item->used, $bytes)) {
  80. $item->setInc('used', $bytes);
  81. } else {
  82. $bytes = bcsub($bytes, bcsub($item->traffic, $item->used));
  83. $item->used = $item->traffic;
  84. $item->is_usable = 0;
  85. $item->save();
  86. }
  87. }
  88. return true;
  89. }
  90. }