mdbq 4.0.114__tar.gz → 4.0.116__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of mdbq might be problematic. Click here for more details.
- {mdbq-4.0.114 → mdbq-4.0.116}/PKG-INFO +1 -1
- mdbq-4.0.116/mdbq/__version__.py +1 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq/redis/redis_cache.py +131 -79
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq.egg-info/PKG-INFO +1 -1
- mdbq-4.0.114/mdbq/__version__.py +0 -1
- {mdbq-4.0.114 → mdbq-4.0.116}/README.txt +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq/__init__.py +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq/auth/__init__.py +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq/auth/auth_backend.py +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq/auth/rate_limiter.py +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq/js/__init__.py +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq/js/jc.py +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq/log/__init__.py +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq/log/mylogger.py +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq/myconf/__init__.py +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq/myconf/myconf.py +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq/mysql/__init__.py +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq/mysql/deduplicator.py +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq/mysql/mysql.py +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq/mysql/s_query.py +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq/mysql/unique_.py +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq/mysql/uploader.py +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq/other/__init__.py +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq/other/download_sku_picture.py +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq/other/error_handler.py +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq/other/otk.py +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq/other/pov_city.py +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq/other/ua_sj.py +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq/pbix/__init__.py +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq/pbix/pbix_refresh.py +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq/pbix/refresh_all.py +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq/redis/__init__.py +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq/redis/getredis.py +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq/route/__init__.py +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq/route/analytics.py +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq/route/monitor.py +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq/route/routes.py +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq/selenium/__init__.py +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq/selenium/get_driver.py +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq/spider/__init__.py +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq.egg-info/SOURCES.txt +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq.egg-info/dependency_links.txt +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/mdbq.egg-info/top_level.txt +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/setup.cfg +0 -0
- {mdbq-4.0.114 → mdbq-4.0.116}/setup.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
VERSION = '4.0.116'
|
|
@@ -44,7 +44,7 @@ logger = mylogger.MyLogger(
|
|
|
44
44
|
|
|
45
45
|
|
|
46
46
|
class CacheStatsCollector:
|
|
47
|
-
"""缓存统计收集器
|
|
47
|
+
"""缓存统计收集器 """
|
|
48
48
|
|
|
49
49
|
def __init__(self, enabled: bool = True, mysql_pool=None, config: dict = None):
|
|
50
50
|
self.enabled = enabled
|
|
@@ -67,10 +67,20 @@ class CacheStatsCollector:
|
|
|
67
67
|
self.response_times = deque(maxlen=1000)
|
|
68
68
|
self.namespace_stats = defaultdict(int)
|
|
69
69
|
|
|
70
|
-
#
|
|
71
|
-
self.submit_interval = self.config.get('submit_interval',
|
|
70
|
+
# 定时提交控制
|
|
71
|
+
self.submit_interval = self.config.get('submit_interval', 600) # 每隔N秒定时提交一次(期间有新操作时)
|
|
72
72
|
self.last_submit_time = time.time()
|
|
73
|
-
self.
|
|
73
|
+
self.last_operation_count = 0 # 上次提交时的操作总数
|
|
74
|
+
|
|
75
|
+
# 后台定时器
|
|
76
|
+
self._timer = None
|
|
77
|
+
self._shutdown_event = threading.Event()
|
|
78
|
+
self._error_count = 0 # 连续错误计数
|
|
79
|
+
self._max_errors = 5 # 最大连续错误次数
|
|
80
|
+
|
|
81
|
+
# 启动后台定时提交
|
|
82
|
+
if self.enabled and self.mysql_pool:
|
|
83
|
+
self._start_background_timer()
|
|
74
84
|
|
|
75
85
|
def record_operation(self, operation: str, response_time: float = 0, namespace: str = ""):
|
|
76
86
|
"""记录操作统计"""
|
|
@@ -101,15 +111,6 @@ class CacheStatsCollector:
|
|
|
101
111
|
'operation': operation,
|
|
102
112
|
'submit_error': str(submit_error)
|
|
103
113
|
})
|
|
104
|
-
|
|
105
|
-
logger.debug("缓存操作统计已记录", {
|
|
106
|
-
'operation': operation,
|
|
107
|
-
'response_time_ms': round(response_time, 2),
|
|
108
|
-
'namespace': namespace,
|
|
109
|
-
'process_id': self.process_id,
|
|
110
|
-
'old_total_operations': old_total,
|
|
111
|
-
'new_total_operations': self.stats['total_operations']
|
|
112
|
-
})
|
|
113
114
|
except Exception as e:
|
|
114
115
|
# 统计记录失败不应影响缓存操作
|
|
115
116
|
logger.error("统计记录失败,但缓存操作继续", {
|
|
@@ -119,69 +120,104 @@ class CacheStatsCollector:
|
|
|
119
120
|
'error': str(e)
|
|
120
121
|
})
|
|
121
122
|
|
|
122
|
-
def
|
|
123
|
-
"""
|
|
123
|
+
def _start_background_timer(self):
|
|
124
|
+
"""启动后台定时提交线程"""
|
|
125
|
+
if self._timer is not None:
|
|
126
|
+
return # 已经启动
|
|
127
|
+
|
|
128
|
+
logger.debug("启动后台定时提交", {
|
|
129
|
+
'instance_name': self.instance_name,
|
|
130
|
+
'submit_interval': self.submit_interval
|
|
131
|
+
})
|
|
132
|
+
|
|
133
|
+
self._timer = threading.Timer(self.submit_interval, self._background_submit)
|
|
134
|
+
self._timer.daemon = True # 设置为守护线程
|
|
135
|
+
self._timer.start()
|
|
136
|
+
|
|
137
|
+
def _background_submit(self):
|
|
138
|
+
"""后台定时提交方法"""
|
|
139
|
+
if self._shutdown_event.is_set():
|
|
140
|
+
return # 已关闭,不再提交
|
|
141
|
+
|
|
142
|
+
try:
|
|
143
|
+
# 执行提交检查(强制检查,不受时间间隔限制)
|
|
144
|
+
self._check_and_submit(force_check=True)
|
|
145
|
+
# 成功执行,重置错误计数
|
|
146
|
+
self._error_count = 0
|
|
147
|
+
|
|
148
|
+
except Exception as e:
|
|
149
|
+
self._error_count += 1
|
|
150
|
+
logger.error("后台定时提交失败", {
|
|
151
|
+
'instance_name': self.instance_name,
|
|
152
|
+
'process_id': self.process_id,
|
|
153
|
+
'error': str(e),
|
|
154
|
+
'error_type': type(e).__name__,
|
|
155
|
+
'error_count': self._error_count,
|
|
156
|
+
'max_errors': self._max_errors
|
|
157
|
+
})
|
|
158
|
+
|
|
159
|
+
# 如果连续错误次数过多,停止定时器
|
|
160
|
+
if self._error_count >= self._max_errors:
|
|
161
|
+
logger.error("后台定时器连续错误过多,停止定时提交", {
|
|
162
|
+
'instance_name': self.instance_name,
|
|
163
|
+
'process_id': self.process_id,
|
|
164
|
+
'error_count': self._error_count
|
|
165
|
+
})
|
|
166
|
+
return # 不再安排下一次定时器
|
|
167
|
+
|
|
168
|
+
finally:
|
|
169
|
+
# 安排下一次定时提交(仅在未达到最大错误次数时)
|
|
170
|
+
if not self._shutdown_event.is_set() and self._error_count < self._max_errors:
|
|
171
|
+
self._timer = threading.Timer(self.submit_interval, self._background_submit)
|
|
172
|
+
self._timer.daemon = True
|
|
173
|
+
self._timer.start()
|
|
174
|
+
|
|
175
|
+
def _check_and_submit(self, force_check=False):
|
|
176
|
+
"""检查并提交统计数据
|
|
177
|
+
|
|
178
|
+
Args:
|
|
179
|
+
force_check: 是否强制检查(用于后台定时器)
|
|
180
|
+
"""
|
|
124
181
|
if not self.mysql_pool:
|
|
125
182
|
return
|
|
126
183
|
|
|
127
184
|
current_time = time.time()
|
|
128
185
|
time_since_last_submit = current_time - self.last_submit_time
|
|
129
|
-
should_submit = False
|
|
130
|
-
reason = ""
|
|
131
|
-
|
|
132
|
-
# 重构后的提交逻辑:
|
|
133
|
-
# 1. 每N次操作提交一次,但每X秒内只能提交一次(防止频繁提交)
|
|
134
|
-
# 2. 每隔X秒提交一次,但必须满足N次操作
|
|
135
|
-
|
|
136
|
-
if self.stats['total_operations'] % self.submit_interval == 0:
|
|
137
|
-
# 达到操作次数阈值
|
|
138
|
-
if time_since_last_submit >= self.min_submit_interval:
|
|
139
|
-
# 满足时间间隔要求,可以提交
|
|
140
|
-
should_submit = True
|
|
141
|
-
reason = f"达到操作次数阈值({self.submit_interval}次)且满足时间间隔({self.min_submit_interval}秒)"
|
|
142
|
-
else:
|
|
143
|
-
# 时间间隔不够,延迟提交
|
|
144
|
-
remaining_time = self.min_submit_interval - time_since_last_submit
|
|
145
|
-
logger.debug("操作次数达标但时间间隔不足,延迟提交", {
|
|
146
|
-
'instance_name': self.instance_name,
|
|
147
|
-
'process_id': self.process_id,
|
|
148
|
-
'total_operations': self.stats['total_operations'],
|
|
149
|
-
'time_since_last_submit': round(time_since_last_submit, 2),
|
|
150
|
-
'remaining_time': round(remaining_time, 2)
|
|
151
|
-
})
|
|
152
|
-
elif time_since_last_submit >= self.min_submit_interval:
|
|
153
|
-
# 达到时间间隔阈值
|
|
154
|
-
if self.stats['total_operations'] >= self.submit_interval:
|
|
155
|
-
# 满足操作次数要求,可以提交
|
|
156
|
-
should_submit = True
|
|
157
|
-
reason = f"达到时间间隔阈值({self.min_submit_interval}秒)且满足操作次数({self.submit_interval}次)"
|
|
158
|
-
else:
|
|
159
|
-
# 操作次数不够,不提交
|
|
160
|
-
logger.debug("时间间隔达标但操作次数不足,暂不提交", {
|
|
161
|
-
'instance_name': self.instance_name,
|
|
162
|
-
'process_id': self.process_id,
|
|
163
|
-
'total_operations': self.stats['total_operations'],
|
|
164
|
-
'required_operations': self.submit_interval,
|
|
165
|
-
'time_since_last_submit': round(time_since_last_submit, 2)
|
|
166
|
-
})
|
|
167
186
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
187
|
+
# 提交逻辑:每隔固定秒数且期间有新操作则提交
|
|
188
|
+
should_check_time = force_check or time_since_last_submit >= self.submit_interval
|
|
189
|
+
|
|
190
|
+
if should_check_time:
|
|
191
|
+
# 检查是否有新的操作(与上次提交时相比)
|
|
192
|
+
new_operations = self.stats['total_operations'] - self.last_operation_count
|
|
193
|
+
|
|
194
|
+
if new_operations > 0:
|
|
195
|
+
# 有新操作,提交统计数据
|
|
196
|
+
try:
|
|
197
|
+
self._submit_to_mysql()
|
|
198
|
+
self.last_submit_time = current_time
|
|
199
|
+
self.last_operation_count = self.stats['total_operations']
|
|
200
|
+
|
|
201
|
+
logger.info("统计数据提交成功", {
|
|
202
|
+
'instance_name': self.instance_name,
|
|
203
|
+
'total_operations': self.stats['total_operations'],
|
|
204
|
+
'new_operations': new_operations,
|
|
205
|
+
'trigger_type': 'background_timer' if force_check else 'operation_triggered'
|
|
206
|
+
})
|
|
207
|
+
except Exception as e:
|
|
208
|
+
logger.error("统计数据提交失败", {
|
|
209
|
+
'instance_name': self.instance_name,
|
|
210
|
+
'error': str(e),
|
|
211
|
+
'trigger_type': 'background_timer' if force_check else 'operation_triggered'
|
|
212
|
+
})
|
|
213
|
+
else:
|
|
214
|
+
# 无新操作,跳过提交但更新时间
|
|
171
215
|
self.last_submit_time = current_time
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
'reason': reason
|
|
178
|
-
})
|
|
179
|
-
except Exception as e:
|
|
180
|
-
logger.error("统计数据提交失败", {
|
|
181
|
-
'instance_name': self.instance_name,
|
|
182
|
-
'process_id': self.process_id,
|
|
183
|
-
'error': str(e)
|
|
184
|
-
})
|
|
216
|
+
if force_check: # 仅在后台定时器触发时记录
|
|
217
|
+
logger.debug("后台检查:无新操作,跳过提交", {
|
|
218
|
+
'instance_name': self.instance_name,
|
|
219
|
+
'total_operations': self.stats['total_operations']
|
|
220
|
+
})
|
|
185
221
|
|
|
186
222
|
def _submit_to_mysql(self):
|
|
187
223
|
"""同步提交统计数据到MySQL"""
|
|
@@ -191,15 +227,17 @@ class CacheStatsCollector:
|
|
|
191
227
|
stats_data = self.get_stats()
|
|
192
228
|
if not stats_data.get('enabled'):
|
|
193
229
|
return
|
|
230
|
+
|
|
231
|
+
db_name = self.config.get('db_name', 'redis_stats')
|
|
232
|
+
table_name = self.config.get('table_name', 'cache_performance')
|
|
194
233
|
|
|
195
234
|
try:
|
|
196
235
|
connection = self.mysql_pool.connection()
|
|
197
236
|
with connection.cursor() as cursor:
|
|
198
237
|
# 选择数据库
|
|
199
|
-
cursor.execute(f"USE `{
|
|
238
|
+
cursor.execute(f"USE `{db_name}`")
|
|
200
239
|
|
|
201
240
|
# 插入统计数据
|
|
202
|
-
table_name = self.config.get('table_name', 'cache_performance')
|
|
203
241
|
insert_sql = f"""
|
|
204
242
|
INSERT INTO `{table_name}` (
|
|
205
243
|
`日期`, `实例标识`, `主机名`, `进程ID`, `统计时间`,
|
|
@@ -232,9 +270,10 @@ class CacheStatsCollector:
|
|
|
232
270
|
connection.close()
|
|
233
271
|
|
|
234
272
|
except Exception as e:
|
|
235
|
-
logger.error("MySQL
|
|
273
|
+
logger.error("MySQL提交失败", {
|
|
236
274
|
'instance_name': self.instance_name,
|
|
237
|
-
'
|
|
275
|
+
'database': db_name,
|
|
276
|
+
'table': table_name,
|
|
238
277
|
'error': str(e)
|
|
239
278
|
})
|
|
240
279
|
raise
|
|
@@ -266,6 +305,20 @@ class CacheStatsCollector:
|
|
|
266
305
|
'process_id': self.process_id
|
|
267
306
|
}
|
|
268
307
|
|
|
308
|
+
def shutdown(self):
|
|
309
|
+
"""关闭统计收集器,停止后台定时器"""
|
|
310
|
+
logger.info("关闭统计收集器", {
|
|
311
|
+
'instance_name': self.instance_name
|
|
312
|
+
})
|
|
313
|
+
|
|
314
|
+
# 设置关闭标志
|
|
315
|
+
self._shutdown_event.set()
|
|
316
|
+
|
|
317
|
+
# 取消定时器
|
|
318
|
+
if self._timer is not None:
|
|
319
|
+
self._timer.cancel()
|
|
320
|
+
self._timer = None
|
|
321
|
+
|
|
269
322
|
def reset_stats(self):
|
|
270
323
|
"""重置统计数据"""
|
|
271
324
|
if not self.enabled:
|
|
@@ -284,6 +337,7 @@ class CacheStatsCollector:
|
|
|
284
337
|
self.response_times.clear()
|
|
285
338
|
self.namespace_stats.clear()
|
|
286
339
|
self.last_submit_time = time.time()
|
|
340
|
+
self.last_operation_count = 0
|
|
287
341
|
|
|
288
342
|
|
|
289
343
|
class CacheSystemState(enum.Enum):
|
|
@@ -300,8 +354,7 @@ class CacheConfig:
|
|
|
300
354
|
def __init__(self, **kwargs):
|
|
301
355
|
# 基础配置
|
|
302
356
|
self.default_ttl = kwargs.get('default_ttl', 3600) # 默认过期时间(秒)
|
|
303
|
-
self.
|
|
304
|
-
self.stats_initial_delay = kwargs.get('stats_initial_delay', 300) # 最少N秒提交一次
|
|
357
|
+
self.stats_submit_interval = kwargs.get('stats_submit_interval', 600) # 每隔N秒定时提交一次(期间有新操作时)
|
|
305
358
|
self.enable_stats = kwargs.get('enable_stats', True) # 是否启用统计功能
|
|
306
359
|
self.max_value_size = kwargs.get('max_value_size', 10 * 1024 * 1024) # 最大值大小(字节)
|
|
307
360
|
self.cache_prefix = kwargs.get('cache_prefix', 'cache') # 缓存键前缀
|
|
@@ -343,8 +396,7 @@ class SmartCacheSystem:
|
|
|
343
396
|
mysql_pool=self.mysql_pool,
|
|
344
397
|
config={
|
|
345
398
|
'instance_name': self.instance_name,
|
|
346
|
-
'submit_interval': self.config.
|
|
347
|
-
'min_submit_interval': 300, # 最少N秒提交一次
|
|
399
|
+
'submit_interval': self.config.stats_submit_interval, # 每隔N秒定时提交一次(期间有新操作时)
|
|
348
400
|
'table_name': self.config.table_name,
|
|
349
401
|
'db_name': self.config.db_name
|
|
350
402
|
}
|
|
@@ -781,8 +833,8 @@ class SmartCacheSystem:
|
|
|
781
833
|
self._state = CacheSystemState.SHUTDOWN
|
|
782
834
|
|
|
783
835
|
if self.stats_collector:
|
|
784
|
-
#
|
|
785
|
-
self.stats_collector.
|
|
836
|
+
# 关闭统计收集器(包括后台定时器)
|
|
837
|
+
self.stats_collector.shutdown()
|
|
786
838
|
|
|
787
839
|
logger.info("缓存系统已关闭", {'instance_name': self.instance_name})
|
|
788
840
|
|
mdbq-4.0.114/mdbq/__version__.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
VERSION = '4.0.114'
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|