crawlo 1.4.1__py3-none-any.whl → 1.4.3__py3-none-any.whl
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 crawlo might be problematic. Click here for more details.
- crawlo/__init__.py +93 -93
- crawlo/__version__.py +1 -1
- crawlo/cli.py +75 -75
- crawlo/commands/__init__.py +14 -14
- crawlo/commands/check.py +594 -594
- crawlo/commands/genspider.py +151 -151
- crawlo/commands/help.py +138 -138
- crawlo/commands/list.py +155 -155
- crawlo/commands/run.py +341 -341
- crawlo/commands/startproject.py +436 -436
- crawlo/commands/stats.py +187 -187
- crawlo/commands/utils.py +196 -196
- crawlo/config.py +312 -312
- crawlo/config_validator.py +277 -277
- crawlo/core/__init__.py +52 -52
- crawlo/core/engine.py +438 -439
- crawlo/core/processor.py +47 -47
- crawlo/core/scheduler.py +291 -257
- crawlo/crawler.py +650 -650
- crawlo/data/__init__.py +5 -5
- crawlo/data/user_agents.py +194 -194
- crawlo/downloader/__init__.py +273 -273
- crawlo/downloader/aiohttp_downloader.py +233 -228
- crawlo/downloader/cffi_downloader.py +245 -245
- crawlo/downloader/httpx_downloader.py +259 -259
- crawlo/downloader/hybrid_downloader.py +212 -212
- crawlo/downloader/playwright_downloader.py +402 -402
- crawlo/downloader/selenium_downloader.py +472 -472
- crawlo/event.py +11 -11
- crawlo/exceptions.py +81 -81
- crawlo/extension/__init__.py +63 -63
- crawlo/extension/health_check.py +141 -141
- crawlo/extension/log_interval.py +94 -94
- crawlo/extension/log_stats.py +70 -70
- crawlo/extension/logging_extension.py +61 -61
- crawlo/extension/memory_monitor.py +104 -104
- crawlo/extension/performance_profiler.py +133 -133
- crawlo/extension/request_recorder.py +107 -107
- crawlo/factories/__init__.py +27 -27
- crawlo/factories/base.py +68 -68
- crawlo/factories/crawler.py +103 -103
- crawlo/factories/registry.py +84 -84
- crawlo/filters/__init__.py +154 -154
- crawlo/filters/aioredis_filter.py +257 -257
- crawlo/filters/memory_filter.py +269 -269
- crawlo/framework.py +292 -292
- crawlo/initialization/__init__.py +44 -44
- crawlo/initialization/built_in.py +425 -425
- crawlo/initialization/context.py +141 -141
- crawlo/initialization/core.py +193 -193
- crawlo/initialization/phases.py +148 -148
- crawlo/initialization/registry.py +145 -145
- crawlo/items/__init__.py +23 -23
- crawlo/items/base.py +23 -23
- crawlo/items/fields.py +52 -52
- crawlo/items/items.py +104 -104
- crawlo/logging/__init__.py +45 -37
- crawlo/logging/async_handler.py +181 -0
- crawlo/logging/config.py +196 -96
- crawlo/logging/factory.py +171 -128
- crawlo/logging/manager.py +111 -111
- crawlo/logging/monitor.py +153 -0
- crawlo/logging/sampler.py +167 -0
- crawlo/middleware/__init__.py +21 -21
- crawlo/middleware/default_header.py +132 -132
- crawlo/middleware/download_delay.py +104 -104
- crawlo/middleware/middleware_manager.py +135 -135
- crawlo/middleware/offsite.py +123 -123
- crawlo/middleware/proxy.py +386 -386
- crawlo/middleware/request_ignore.py +86 -86
- crawlo/middleware/response_code.py +150 -150
- crawlo/middleware/response_filter.py +136 -136
- crawlo/middleware/retry.py +124 -124
- crawlo/middleware/simple_proxy.py +65 -65
- crawlo/mode_manager.py +219 -219
- crawlo/network/__init__.py +21 -21
- crawlo/network/request.py +379 -379
- crawlo/network/response.py +359 -359
- crawlo/pipelines/__init__.py +21 -21
- crawlo/pipelines/bloom_dedup_pipeline.py +146 -146
- crawlo/pipelines/console_pipeline.py +39 -39
- crawlo/pipelines/csv_pipeline.py +316 -316
- crawlo/pipelines/database_dedup_pipeline.py +197 -197
- crawlo/pipelines/json_pipeline.py +218 -218
- crawlo/pipelines/memory_dedup_pipeline.py +105 -105
- crawlo/pipelines/mongo_pipeline.py +131 -131
- crawlo/pipelines/mysql_pipeline.py +325 -325
- crawlo/pipelines/pipeline_manager.py +100 -84
- crawlo/pipelines/redis_dedup_pipeline.py +156 -156
- crawlo/project.py +349 -338
- crawlo/queue/pqueue.py +42 -42
- crawlo/queue/queue_manager.py +526 -522
- crawlo/queue/redis_priority_queue.py +370 -367
- crawlo/settings/__init__.py +7 -7
- crawlo/settings/default_settings.py +284 -284
- crawlo/settings/setting_manager.py +219 -219
- crawlo/spider/__init__.py +657 -657
- crawlo/stats_collector.py +73 -73
- crawlo/subscriber.py +129 -129
- crawlo/task_manager.py +138 -138
- crawlo/templates/crawlo.cfg.tmpl +10 -10
- crawlo/templates/project/__init__.py.tmpl +3 -3
- crawlo/templates/project/items.py.tmpl +17 -17
- crawlo/templates/project/middlewares.py.tmpl +118 -118
- crawlo/templates/project/pipelines.py.tmpl +96 -96
- crawlo/templates/project/settings.py.tmpl +170 -170
- crawlo/templates/project/settings_distributed.py.tmpl +169 -169
- crawlo/templates/project/settings_gentle.py.tmpl +166 -166
- crawlo/templates/project/settings_high_performance.py.tmpl +167 -167
- crawlo/templates/project/settings_minimal.py.tmpl +65 -65
- crawlo/templates/project/settings_simple.py.tmpl +164 -164
- crawlo/templates/project/spiders/__init__.py.tmpl +9 -9
- crawlo/templates/run.py.tmpl +34 -34
- crawlo/templates/spider/spider.py.tmpl +143 -143
- crawlo/templates/spiders_init.py.tmpl +9 -9
- crawlo/tools/__init__.py +200 -200
- crawlo/tools/anti_crawler.py +268 -268
- crawlo/tools/authenticated_proxy.py +240 -240
- crawlo/tools/data_formatter.py +225 -225
- crawlo/tools/data_validator.py +180 -180
- crawlo/tools/date_tools.py +289 -289
- crawlo/tools/distributed_coordinator.py +384 -384
- crawlo/tools/encoding_converter.py +127 -127
- crawlo/tools/network_diagnostic.py +364 -364
- crawlo/tools/request_tools.py +82 -82
- crawlo/tools/retry_mechanism.py +224 -224
- crawlo/tools/scenario_adapter.py +262 -262
- crawlo/tools/text_cleaner.py +232 -232
- crawlo/utils/__init__.py +34 -34
- crawlo/utils/batch_processor.py +259 -259
- crawlo/utils/class_loader.py +25 -25
- crawlo/utils/controlled_spider_mixin.py +439 -439
- crawlo/utils/db_helper.py +343 -343
- crawlo/utils/enhanced_error_handler.py +356 -356
- crawlo/utils/env_config.py +142 -142
- crawlo/utils/error_handler.py +165 -165
- crawlo/utils/fingerprint.py +122 -122
- crawlo/utils/func_tools.py +82 -82
- crawlo/utils/large_scale_config.py +286 -286
- crawlo/utils/large_scale_helper.py +344 -344
- crawlo/utils/log.py +79 -79
- crawlo/utils/performance_monitor.py +285 -285
- crawlo/utils/queue_helper.py +175 -175
- crawlo/utils/redis_connection_pool.py +388 -388
- crawlo/utils/redis_key_validator.py +198 -198
- crawlo/utils/request.py +267 -267
- crawlo/utils/request_serializer.py +225 -225
- crawlo/utils/spider_loader.py +61 -61
- crawlo/utils/system.py +11 -11
- crawlo/utils/tools.py +4 -4
- crawlo/utils/url.py +39 -39
- crawlo-1.4.3.dist-info/METADATA +190 -0
- crawlo-1.4.3.dist-info/RECORD +326 -0
- examples/__init__.py +7 -7
- examples/test_project/__init__.py +7 -7
- examples/test_project/run.py +34 -34
- examples/test_project/test_project/__init__.py +3 -3
- examples/test_project/test_project/items.py +17 -17
- examples/test_project/test_project/middlewares.py +118 -118
- examples/test_project/test_project/pipelines.py +96 -96
- examples/test_project/test_project/settings.py +169 -169
- examples/test_project/test_project/spiders/__init__.py +9 -9
- examples/test_project/test_project/spiders/of_week_dis.py +143 -143
- tests/__init__.py +7 -7
- tests/advanced_tools_example.py +275 -275
- tests/authenticated_proxy_example.py +106 -106
- tests/baidu_performance_test.py +108 -108
- tests/baidu_test.py +59 -59
- tests/cleaners_example.py +160 -160
- tests/comprehensive_framework_test.py +212 -212
- tests/comprehensive_test.py +81 -81
- tests/comprehensive_testing_summary.md +186 -186
- tests/config_validation_demo.py +142 -142
- tests/controlled_spider_example.py +205 -205
- tests/date_tools_example.py +180 -180
- tests/debug_configure.py +69 -69
- tests/debug_framework_logger.py +84 -84
- tests/debug_log_config.py +126 -126
- tests/debug_log_levels.py +63 -63
- tests/debug_pipelines.py +66 -66
- tests/detailed_log_test.py +233 -233
- tests/distributed_test.py +66 -66
- tests/distributed_test_debug.py +76 -76
- tests/dynamic_loading_example.py +523 -523
- tests/dynamic_loading_test.py +104 -104
- tests/env_config_example.py +133 -133
- tests/error_handling_example.py +171 -171
- tests/final_comprehensive_test.py +151 -151
- tests/final_log_test.py +260 -260
- tests/final_validation_test.py +182 -182
- tests/fix_log_test.py +142 -142
- tests/framework_performance_test.py +202 -202
- tests/log_buffering_test.py +111 -111
- tests/log_generation_timing_test.py +153 -153
- tests/optimized_performance_test.py +211 -211
- tests/performance_comparison.py +245 -245
- tests/queue_blocking_test.py +113 -113
- tests/queue_test.py +89 -89
- tests/redis_key_validation_demo.py +130 -130
- tests/request_params_example.py +150 -150
- tests/response_improvements_example.py +144 -144
- tests/scrapy_comparison/ofweek_scrapy.py +138 -138
- tests/scrapy_comparison/scrapy_test.py +133 -133
- tests/simple_command_test.py +119 -119
- tests/simple_crawlo_test.py +127 -127
- tests/simple_log_test.py +57 -57
- tests/simple_log_test2.py +137 -137
- tests/simple_optimization_test.py +128 -128
- tests/simple_queue_type_test.py +41 -41
- tests/simple_spider_test.py +49 -49
- tests/simple_test.py +47 -47
- tests/spider_log_timing_test.py +177 -177
- tests/test_advanced_tools.py +148 -148
- tests/test_all_commands.py +230 -230
- tests/test_all_pipeline_fingerprints.py +133 -133
- tests/test_all_redis_key_configs.py +145 -145
- tests/test_authenticated_proxy.py +141 -141
- tests/test_batch_processor.py +178 -178
- tests/test_cleaners.py +54 -54
- tests/test_component_factory.py +174 -174
- tests/test_comprehensive.py +146 -146
- tests/test_config_consistency.py +80 -80
- tests/test_config_merge.py +152 -152
- tests/test_config_validator.py +182 -182
- tests/test_controlled_spider_mixin.py +79 -79
- tests/test_crawlo_proxy_integration.py +108 -108
- tests/test_date_tools.py +123 -123
- tests/test_dedup_fix.py +220 -220
- tests/test_dedup_pipeline_consistency.py +125 -0
- tests/test_default_header_middleware.py +313 -313
- tests/test_distributed.py +65 -65
- tests/test_double_crawlo_fix.py +204 -204
- tests/test_double_crawlo_fix_simple.py +124 -124
- tests/test_download_delay_middleware.py +221 -221
- tests/test_downloader_proxy_compatibility.py +268 -268
- tests/test_dynamic_downloaders_proxy.py +124 -124
- tests/test_dynamic_proxy.py +92 -92
- tests/test_dynamic_proxy_config.py +146 -146
- tests/test_dynamic_proxy_real.py +109 -109
- tests/test_edge_cases.py +303 -303
- tests/test_enhanced_error_handler.py +270 -270
- tests/test_enhanced_error_handler_comprehensive.py +245 -245
- tests/test_env_config.py +121 -121
- tests/test_error_handler_compatibility.py +112 -112
- tests/test_factories.py +252 -252
- tests/test_final_validation.py +153 -153
- tests/test_fingerprint_consistency.py +135 -135
- tests/test_fingerprint_simple.py +51 -51
- tests/test_framework_env_usage.py +103 -103
- tests/test_framework_logger.py +66 -66
- tests/test_framework_startup.py +64 -64
- tests/test_get_component_logger.py +83 -83
- tests/test_hash_performance.py +99 -99
- tests/test_integration.py +169 -169
- tests/test_item_dedup_redis_key.py +122 -122
- tests/test_large_scale_config.py +112 -112
- tests/test_large_scale_helper.py +235 -235
- tests/test_logging_enhancements.py +375 -0
- tests/test_logging_final.py +185 -0
- tests/test_logging_integration.py +313 -0
- tests/test_logging_system.py +282 -282
- tests/test_middleware_debug.py +142 -0
- tests/test_mode_change.py +72 -72
- tests/test_mode_consistency.py +51 -51
- tests/test_offsite_middleware.py +244 -244
- tests/test_offsite_middleware_simple.py +203 -203
- tests/test_parsel.py +29 -29
- tests/test_performance.py +327 -327
- tests/test_performance_monitor.py +115 -115
- tests/test_pipeline_fingerprint_consistency.py +86 -86
- tests/test_priority_behavior.py +212 -0
- tests/test_priority_consistency.py +152 -0
- tests/test_priority_consistency_fixed.py +250 -0
- tests/test_proxy_api.py +264 -264
- tests/test_proxy_health_check.py +32 -32
- tests/test_proxy_middleware.py +121 -121
- tests/test_proxy_middleware_enhanced.py +216 -216
- tests/test_proxy_middleware_integration.py +136 -136
- tests/test_proxy_middleware_refactored.py +184 -184
- tests/test_proxy_providers.py +56 -56
- tests/test_proxy_stats.py +19 -19
- tests/test_proxy_strategies.py +59 -59
- tests/test_queue_empty_check.py +41 -41
- tests/test_queue_manager_double_crawlo.py +173 -173
- tests/test_queue_manager_redis_key.py +179 -179
- tests/test_queue_naming.py +154 -154
- tests/test_queue_type.py +106 -106
- tests/test_queue_type_redis_config_consistency.py +131 -0
- tests/test_random_headers_default.py +323 -0
- tests/test_random_headers_necessity.py +309 -0
- tests/test_random_user_agent.py +72 -72
- tests/test_real_scenario_proxy.py +195 -195
- tests/test_redis_config.py +28 -28
- tests/test_redis_connection_pool.py +294 -294
- tests/test_redis_key_naming.py +181 -181
- tests/test_redis_key_validator.py +123 -123
- tests/test_redis_queue.py +224 -224
- tests/test_redis_queue_name_fix.py +175 -175
- tests/test_redis_queue_type_fallback.py +130 -0
- tests/test_request_ignore_middleware.py +182 -182
- tests/test_request_params.py +111 -111
- tests/test_request_serialization.py +70 -70
- tests/test_response_code_middleware.py +349 -349
- tests/test_response_filter_middleware.py +427 -427
- tests/test_response_improvements.py +152 -152
- tests/test_retry_middleware.py +334 -242
- tests/test_retry_middleware_realistic.py +274 -0
- tests/test_scheduler.py +252 -252
- tests/test_scheduler_config_update.py +133 -133
- tests/test_simple_response.py +61 -61
- tests/test_telecom_spider_redis_key.py +205 -205
- tests/test_template_content.py +87 -87
- tests/test_template_redis_key.py +134 -134
- tests/test_tools.py +159 -159
- tests/test_user_agent_randomness.py +177 -0
- tests/test_user_agents.py +96 -96
- tests/tools_example.py +260 -260
- tests/untested_features_report.md +138 -138
- tests/verify_debug.py +51 -51
- tests/verify_distributed.py +117 -117
- tests/verify_log_fix.py +111 -111
- crawlo-1.4.1.dist-info/METADATA +0 -1199
- crawlo-1.4.1.dist-info/RECORD +0 -309
- {crawlo-1.4.1.dist-info → crawlo-1.4.3.dist-info}/WHEEL +0 -0
- {crawlo-1.4.1.dist-info → crawlo-1.4.3.dist-info}/entry_points.txt +0 -0
- {crawlo-1.4.1.dist-info → crawlo-1.4.3.dist-info}/top_level.txt +0 -0
tests/test_redis_queue.py
CHANGED
|
@@ -1,225 +1,225 @@
|
|
|
1
|
-
#!/usr/bin/env python3
|
|
2
|
-
# -*- coding: utf-8 -*-
|
|
3
|
-
"""
|
|
4
|
-
Redis 分布式队列测试脚本
|
|
5
|
-
用于诊断和修复分布式队列问题
|
|
6
|
-
"""
|
|
7
|
-
import asyncio
|
|
8
|
-
import sys
|
|
9
|
-
import traceback
|
|
10
|
-
import time
|
|
11
|
-
from crawlo.queue.redis_priority_queue import RedisPriorityQueue
|
|
12
|
-
from crawlo.network.request import Request
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
async def test_redis_connection():
|
|
16
|
-
"""测试 Redis 连接"""
|
|
17
|
-
print("🔍 1. 测试 Redis 连接...")
|
|
18
|
-
|
|
19
|
-
# 测试不同的 Redis URL 格式
|
|
20
|
-
test_urls = [
|
|
21
|
-
"redis://localhost:6379/0",
|
|
22
|
-
"redis://:oscar&0503@127.0.0.1:6379/0", # 带密码
|
|
23
|
-
"redis://127.0.0.1:6379/0", # 无密码
|
|
24
|
-
]
|
|
25
|
-
|
|
26
|
-
for redis_url in test_urls:
|
|
27
|
-
try:
|
|
28
|
-
print(f" 尝试连接: {redis_url}")
|
|
29
|
-
queue = RedisPriorityQueue(redis_url=redis_url)
|
|
30
|
-
await queue.connect()
|
|
31
|
-
print(f" 连接成功: {redis_url}")
|
|
32
|
-
await queue.close()
|
|
33
|
-
return redis_url
|
|
34
|
-
except Exception as e:
|
|
35
|
-
print(f" 连接失败: {redis_url} - {e}")
|
|
36
|
-
|
|
37
|
-
raise ConnectionError("所有 Redis URL 都连接失败")
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
async def test_queue_operations(redis_url):
|
|
41
|
-
"""测试队列基本操作"""
|
|
42
|
-
print("🔍 2. 测试队列基本操作...")
|
|
43
|
-
|
|
44
|
-
queue = RedisPriorityQueue(
|
|
45
|
-
redis_url=redis_url,
|
|
46
|
-
queue_name="test:crawlo:requests",
|
|
47
|
-
max_retries=2
|
|
48
|
-
)
|
|
49
|
-
|
|
50
|
-
try:
|
|
51
|
-
await queue.connect()
|
|
52
|
-
|
|
53
|
-
# 测试 put 操作
|
|
54
|
-
test_request = Request(url="https://example.com", priority=5)
|
|
55
|
-
print(f" 📤 插入请求: {test_request.url}")
|
|
56
|
-
|
|
57
|
-
success = await queue.put(test_request, priority=5)
|
|
58
|
-
if success:
|
|
59
|
-
print(" 插入成功")
|
|
60
|
-
else:
|
|
61
|
-
print(" 插入失败")
|
|
62
|
-
return False
|
|
63
|
-
|
|
64
|
-
# 测试队列大小
|
|
65
|
-
size = await queue.qsize()
|
|
66
|
-
print(f" 队列大小: {size}")
|
|
67
|
-
|
|
68
|
-
# 测试 get 操作
|
|
69
|
-
print(" 📥 获取请求...")
|
|
70
|
-
retrieved_request = await queue.get(timeout=2.0)
|
|
71
|
-
|
|
72
|
-
if retrieved_request:
|
|
73
|
-
print(f" 获取成功: {retrieved_request.url}")
|
|
74
|
-
# 测试 ack
|
|
75
|
-
await queue.ack(retrieved_request)
|
|
76
|
-
print(" ACK 成功")
|
|
77
|
-
else:
|
|
78
|
-
print(" 获取失败(超时)")
|
|
79
|
-
return False
|
|
80
|
-
|
|
81
|
-
return True
|
|
82
|
-
|
|
83
|
-
except Exception as e:
|
|
84
|
-
print(f" 队列操作失败: {e}")
|
|
85
|
-
traceback.print_exc()
|
|
86
|
-
return False
|
|
87
|
-
finally:
|
|
88
|
-
await queue.close()
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
async def test_serialization():
|
|
92
|
-
"""测试序列化问题"""
|
|
93
|
-
print("🔍 3. 测试 Request 序列化...")
|
|
94
|
-
|
|
95
|
-
try:
|
|
96
|
-
import pickle
|
|
97
|
-
from crawlo.network.request import Request
|
|
98
|
-
|
|
99
|
-
# 创建测试请求
|
|
100
|
-
request = Request(
|
|
101
|
-
url="https://example.com",
|
|
102
|
-
method="GET",
|
|
103
|
-
headers={"User-Agent": "Test"},
|
|
104
|
-
meta={"test": "data"},
|
|
105
|
-
priority=5
|
|
106
|
-
)
|
|
107
|
-
|
|
108
|
-
# 测试序列化
|
|
109
|
-
serialized = pickle.dumps(request)
|
|
110
|
-
print(f" 序列化成功,大小: {len(serialized)} bytes")
|
|
111
|
-
|
|
112
|
-
# 测试反序列化
|
|
113
|
-
deserialized = pickle.loads(serialized)
|
|
114
|
-
print(f" 反序列化成功: {deserialized.url}")
|
|
115
|
-
|
|
116
|
-
return True
|
|
117
|
-
|
|
118
|
-
except Exception as e:
|
|
119
|
-
print(f" 序列化失败: {e}")
|
|
120
|
-
traceback.print_exc()
|
|
121
|
-
return False
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
async def test_concurrent_operations(redis_url):
|
|
125
|
-
"""测试并发操作"""
|
|
126
|
-
print("🔍 4. 测试并发操作...")
|
|
127
|
-
|
|
128
|
-
async def producer(queue, start_id):
|
|
129
|
-
"""生产者"""
|
|
130
|
-
try:
|
|
131
|
-
for i in range(5):
|
|
132
|
-
request = Request(url=f"https://example{start_id + i}.com", priority=i)
|
|
133
|
-
await queue.put(request, priority=i)
|
|
134
|
-
await asyncio.sleep(0.1)
|
|
135
|
-
print(f" 生产者 {start_id} 完成")
|
|
136
|
-
except Exception as e:
|
|
137
|
-
print(f" 生产者 {start_id} 失败: {e}")
|
|
138
|
-
|
|
139
|
-
async def consumer(queue, consumer_id):
|
|
140
|
-
"""消费者"""
|
|
141
|
-
consumed = 0
|
|
142
|
-
try:
|
|
143
|
-
for _ in range(3): # 每个消费者处理3个请求
|
|
144
|
-
request = await queue.get(timeout=5.0)
|
|
145
|
-
if request:
|
|
146
|
-
await queue.ack(request)
|
|
147
|
-
consumed += 1
|
|
148
|
-
await asyncio.sleep(0.05)
|
|
149
|
-
else:
|
|
150
|
-
break
|
|
151
|
-
print(f" 消费者 {consumer_id} 处理了 {consumed} 个请求")
|
|
152
|
-
except Exception as e:
|
|
153
|
-
print(f" 消费者 {consumer_id} 失败: {e}")
|
|
154
|
-
|
|
155
|
-
queue = RedisPriorityQueue(
|
|
156
|
-
redis_url=redis_url,
|
|
157
|
-
queue_name="test:concurrent:requests"
|
|
158
|
-
)
|
|
159
|
-
|
|
160
|
-
try:
|
|
161
|
-
await queue.connect()
|
|
162
|
-
|
|
163
|
-
# 并发运行生产者和消费者
|
|
164
|
-
tasks = [
|
|
165
|
-
producer(queue, 0),
|
|
166
|
-
producer(queue, 10),
|
|
167
|
-
consumer(queue, 1),
|
|
168
|
-
consumer(queue, 2),
|
|
169
|
-
]
|
|
170
|
-
|
|
171
|
-
await asyncio.gather(*tasks, return_exceptions=True)
|
|
172
|
-
|
|
173
|
-
# 检查剩余队列大小
|
|
174
|
-
final_size = await queue.qsize()
|
|
175
|
-
print(f" 最终队列大小: {final_size}")
|
|
176
|
-
|
|
177
|
-
return True
|
|
178
|
-
|
|
179
|
-
except Exception as e:
|
|
180
|
-
print(f" 并发测试失败: {e}")
|
|
181
|
-
return False
|
|
182
|
-
finally:
|
|
183
|
-
await queue.close()
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
async def main():
|
|
187
|
-
"""主测试函数"""
|
|
188
|
-
print("开始 Redis 分布式队列诊断...")
|
|
189
|
-
print("=" * 50)
|
|
190
|
-
|
|
191
|
-
try:
|
|
192
|
-
# 1. 测试连接
|
|
193
|
-
redis_url = await test_redis_connection()
|
|
194
|
-
|
|
195
|
-
# 2. 测试序列化
|
|
196
|
-
if not await test_serialization():
|
|
197
|
-
return
|
|
198
|
-
|
|
199
|
-
# 3. 测试基本操作
|
|
200
|
-
if not await test_queue_operations(redis_url):
|
|
201
|
-
return
|
|
202
|
-
|
|
203
|
-
# 4. 测试并发操作
|
|
204
|
-
if not await test_concurrent_operations(redis_url):
|
|
205
|
-
return
|
|
206
|
-
|
|
207
|
-
print("=" * 50)
|
|
208
|
-
print("所有测试通过!Redis 队列工作正常")
|
|
209
|
-
|
|
210
|
-
except Exception as e:
|
|
211
|
-
print("=" * 50)
|
|
212
|
-
print(f"诊断失败: {e}")
|
|
213
|
-
traceback.print_exc()
|
|
214
|
-
|
|
215
|
-
# 提供解决建议
|
|
216
|
-
print("\n🔧 可能的解决方案:")
|
|
217
|
-
print("1. 检查 Redis 服务是否启动: redis-server")
|
|
218
|
-
print("2. 检查 Redis 密码配置")
|
|
219
|
-
print("3. 检查防火墙和端口 6379")
|
|
220
|
-
print("4. 安装 Redis: pip install redis")
|
|
221
|
-
print("5. 检查 Redis 配置文件中的 bind 设置")
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
if __name__ == "__main__":
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
# -*- coding: utf-8 -*-
|
|
3
|
+
"""
|
|
4
|
+
Redis 分布式队列测试脚本
|
|
5
|
+
用于诊断和修复分布式队列问题
|
|
6
|
+
"""
|
|
7
|
+
import asyncio
|
|
8
|
+
import sys
|
|
9
|
+
import traceback
|
|
10
|
+
import time
|
|
11
|
+
from crawlo.queue.redis_priority_queue import RedisPriorityQueue
|
|
12
|
+
from crawlo.network.request import Request
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
async def test_redis_connection():
|
|
16
|
+
"""测试 Redis 连接"""
|
|
17
|
+
print("🔍 1. 测试 Redis 连接...")
|
|
18
|
+
|
|
19
|
+
# 测试不同的 Redis URL 格式
|
|
20
|
+
test_urls = [
|
|
21
|
+
"redis://localhost:6379/0",
|
|
22
|
+
"redis://:oscar&0503@127.0.0.1:6379/0", # 带密码
|
|
23
|
+
"redis://127.0.0.1:6379/0", # 无密码
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
for redis_url in test_urls:
|
|
27
|
+
try:
|
|
28
|
+
print(f" 尝试连接: {redis_url}")
|
|
29
|
+
queue = RedisPriorityQueue(redis_url=redis_url)
|
|
30
|
+
await queue.connect()
|
|
31
|
+
print(f" 连接成功: {redis_url}")
|
|
32
|
+
await queue.close()
|
|
33
|
+
return redis_url
|
|
34
|
+
except Exception as e:
|
|
35
|
+
print(f" 连接失败: {redis_url} - {e}")
|
|
36
|
+
|
|
37
|
+
raise ConnectionError("所有 Redis URL 都连接失败")
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
async def test_queue_operations(redis_url):
|
|
41
|
+
"""测试队列基本操作"""
|
|
42
|
+
print("🔍 2. 测试队列基本操作...")
|
|
43
|
+
|
|
44
|
+
queue = RedisPriorityQueue(
|
|
45
|
+
redis_url=redis_url,
|
|
46
|
+
queue_name="test:crawlo:requests",
|
|
47
|
+
max_retries=2
|
|
48
|
+
)
|
|
49
|
+
|
|
50
|
+
try:
|
|
51
|
+
await queue.connect()
|
|
52
|
+
|
|
53
|
+
# 测试 put 操作
|
|
54
|
+
test_request = Request(url="https://example.com", priority=5)
|
|
55
|
+
print(f" 📤 插入请求: {test_request.url}")
|
|
56
|
+
|
|
57
|
+
success = await queue.put(test_request, priority=5)
|
|
58
|
+
if success:
|
|
59
|
+
print(" 插入成功")
|
|
60
|
+
else:
|
|
61
|
+
print(" 插入失败")
|
|
62
|
+
return False
|
|
63
|
+
|
|
64
|
+
# 测试队列大小
|
|
65
|
+
size = await queue.qsize()
|
|
66
|
+
print(f" 队列大小: {size}")
|
|
67
|
+
|
|
68
|
+
# 测试 get 操作
|
|
69
|
+
print(" 📥 获取请求...")
|
|
70
|
+
retrieved_request = await queue.get(timeout=2.0)
|
|
71
|
+
|
|
72
|
+
if retrieved_request:
|
|
73
|
+
print(f" 获取成功: {retrieved_request.url}")
|
|
74
|
+
# 测试 ack
|
|
75
|
+
await queue.ack(retrieved_request)
|
|
76
|
+
print(" ACK 成功")
|
|
77
|
+
else:
|
|
78
|
+
print(" 获取失败(超时)")
|
|
79
|
+
return False
|
|
80
|
+
|
|
81
|
+
return True
|
|
82
|
+
|
|
83
|
+
except Exception as e:
|
|
84
|
+
print(f" 队列操作失败: {e}")
|
|
85
|
+
traceback.print_exc()
|
|
86
|
+
return False
|
|
87
|
+
finally:
|
|
88
|
+
await queue.close()
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
async def test_serialization():
|
|
92
|
+
"""测试序列化问题"""
|
|
93
|
+
print("🔍 3. 测试 Request 序列化...")
|
|
94
|
+
|
|
95
|
+
try:
|
|
96
|
+
import pickle
|
|
97
|
+
from crawlo.network.request import Request
|
|
98
|
+
|
|
99
|
+
# 创建测试请求
|
|
100
|
+
request = Request(
|
|
101
|
+
url="https://example.com",
|
|
102
|
+
method="GET",
|
|
103
|
+
headers={"User-Agent": "Test"},
|
|
104
|
+
meta={"test": "data"},
|
|
105
|
+
priority=5
|
|
106
|
+
)
|
|
107
|
+
|
|
108
|
+
# 测试序列化
|
|
109
|
+
serialized = pickle.dumps(request)
|
|
110
|
+
print(f" 序列化成功,大小: {len(serialized)} bytes")
|
|
111
|
+
|
|
112
|
+
# 测试反序列化
|
|
113
|
+
deserialized = pickle.loads(serialized)
|
|
114
|
+
print(f" 反序列化成功: {deserialized.url}")
|
|
115
|
+
|
|
116
|
+
return True
|
|
117
|
+
|
|
118
|
+
except Exception as e:
|
|
119
|
+
print(f" 序列化失败: {e}")
|
|
120
|
+
traceback.print_exc()
|
|
121
|
+
return False
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
async def test_concurrent_operations(redis_url):
|
|
125
|
+
"""测试并发操作"""
|
|
126
|
+
print("🔍 4. 测试并发操作...")
|
|
127
|
+
|
|
128
|
+
async def producer(queue, start_id):
|
|
129
|
+
"""生产者"""
|
|
130
|
+
try:
|
|
131
|
+
for i in range(5):
|
|
132
|
+
request = Request(url=f"https://example{start_id + i}.com", priority=i)
|
|
133
|
+
await queue.put(request, priority=i)
|
|
134
|
+
await asyncio.sleep(0.1)
|
|
135
|
+
print(f" 生产者 {start_id} 完成")
|
|
136
|
+
except Exception as e:
|
|
137
|
+
print(f" 生产者 {start_id} 失败: {e}")
|
|
138
|
+
|
|
139
|
+
async def consumer(queue, consumer_id):
|
|
140
|
+
"""消费者"""
|
|
141
|
+
consumed = 0
|
|
142
|
+
try:
|
|
143
|
+
for _ in range(3): # 每个消费者处理3个请求
|
|
144
|
+
request = await queue.get(timeout=5.0)
|
|
145
|
+
if request:
|
|
146
|
+
await queue.ack(request)
|
|
147
|
+
consumed += 1
|
|
148
|
+
await asyncio.sleep(0.05)
|
|
149
|
+
else:
|
|
150
|
+
break
|
|
151
|
+
print(f" 消费者 {consumer_id} 处理了 {consumed} 个请求")
|
|
152
|
+
except Exception as e:
|
|
153
|
+
print(f" 消费者 {consumer_id} 失败: {e}")
|
|
154
|
+
|
|
155
|
+
queue = RedisPriorityQueue(
|
|
156
|
+
redis_url=redis_url,
|
|
157
|
+
queue_name="test:concurrent:requests"
|
|
158
|
+
)
|
|
159
|
+
|
|
160
|
+
try:
|
|
161
|
+
await queue.connect()
|
|
162
|
+
|
|
163
|
+
# 并发运行生产者和消费者
|
|
164
|
+
tasks = [
|
|
165
|
+
producer(queue, 0),
|
|
166
|
+
producer(queue, 10),
|
|
167
|
+
consumer(queue, 1),
|
|
168
|
+
consumer(queue, 2),
|
|
169
|
+
]
|
|
170
|
+
|
|
171
|
+
await asyncio.gather(*tasks, return_exceptions=True)
|
|
172
|
+
|
|
173
|
+
# 检查剩余队列大小
|
|
174
|
+
final_size = await queue.qsize()
|
|
175
|
+
print(f" 最终队列大小: {final_size}")
|
|
176
|
+
|
|
177
|
+
return True
|
|
178
|
+
|
|
179
|
+
except Exception as e:
|
|
180
|
+
print(f" 并发测试失败: {e}")
|
|
181
|
+
return False
|
|
182
|
+
finally:
|
|
183
|
+
await queue.close()
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
async def main():
|
|
187
|
+
"""主测试函数"""
|
|
188
|
+
print("开始 Redis 分布式队列诊断...")
|
|
189
|
+
print("=" * 50)
|
|
190
|
+
|
|
191
|
+
try:
|
|
192
|
+
# 1. 测试连接
|
|
193
|
+
redis_url = await test_redis_connection()
|
|
194
|
+
|
|
195
|
+
# 2. 测试序列化
|
|
196
|
+
if not await test_serialization():
|
|
197
|
+
return
|
|
198
|
+
|
|
199
|
+
# 3. 测试基本操作
|
|
200
|
+
if not await test_queue_operations(redis_url):
|
|
201
|
+
return
|
|
202
|
+
|
|
203
|
+
# 4. 测试并发操作
|
|
204
|
+
if not await test_concurrent_operations(redis_url):
|
|
205
|
+
return
|
|
206
|
+
|
|
207
|
+
print("=" * 50)
|
|
208
|
+
print("所有测试通过!Redis 队列工作正常")
|
|
209
|
+
|
|
210
|
+
except Exception as e:
|
|
211
|
+
print("=" * 50)
|
|
212
|
+
print(f"诊断失败: {e}")
|
|
213
|
+
traceback.print_exc()
|
|
214
|
+
|
|
215
|
+
# 提供解决建议
|
|
216
|
+
print("\n🔧 可能的解决方案:")
|
|
217
|
+
print("1. 检查 Redis 服务是否启动: redis-server")
|
|
218
|
+
print("2. 检查 Redis 密码配置")
|
|
219
|
+
print("3. 检查防火墙和端口 6379")
|
|
220
|
+
print("4. 安装 Redis: pip install redis")
|
|
221
|
+
print("5. 检查 Redis 配置文件中的 bind 设置")
|
|
222
|
+
|
|
223
|
+
|
|
224
|
+
if __name__ == "__main__":
|
|
225
225
|
asyncio.run(main())
|