本文目录导读:

我来提供一个完整的任务分发防重复脚本实现方案,包含多种策略:
基于Redis的防重复方案(最推荐)
import redis
import hashlib
import json
import time
from functools import wraps
class TaskDistributor:
def __init__(self, redis_host='localhost', redis_port=6379, db=0):
self.redis = redis.Redis(
host=redis_host,
port=redis_port,
db=db,
decode_responses=True
)
self.lock_prefix = "task:lock:"
self.task_prefix = "task:data:"
self.lock_timeout = 3600 # 1小时锁超时
def _generate_task_id(self, task_data):
"""生成任务唯一ID"""
task_str = json.dumps(task_data, sort_keys=True)
return hashlib.md5(task_str.encode()).hexdigest()
def try_acquire_lock(self, task_id, ttl=None):
"""尝试获取任务锁"""
if ttl is None:
ttl = self.lock_timeout
lock_key = f"{self.lock_prefix}{task_id}"
# 使用setnx实现原子操作
acquired = self.redis.setnx(lock_key, str(time.time()))
if acquired:
# 设置过期时间防止死锁
self.redis.expire(lock_key, ttl)
return True
return False
def distribute_task(self, task_data):
"""分发任务(带防重复)"""
task_id = self._generate_task_id(task_data)
# 尝试获取锁
if not self.try_acquire_lock(task_id):
return {
'status': 'duplicate',
'task_id': task_id,
'message': '任务已存在'
}
# 存储任务数据
task_key = f"{self.task_prefix}{task_id}"
self.redis.setex(task_key, self.lock_timeout, json.dumps(task_data))
# 添加到任务队列
self.redis.lpush('task_queue', task_id)
return {
'status': 'success',
'task_id': task_id,
'message': '任务分发成功'
}
def release_lock(self, task_id):
"""释放任务锁"""
lock_key = f"{self.lock_prefix}{task_id}"
# 使用Lua脚本保证原子性
script = """
if redis.call('get', KEYS[1]) == ARGV[1] then
return redis.call('del', KEYS[1])
else
return 0
end
"""
self.redis.eval(script, 1, lock_key, str(time.time()))
def mark_completed(self, task_id):
"""标记任务完成"""
completed_key = f"task:completed:{task_id}"
self.redis.setex(completed_key, 86400 * 7, time.time()) # 保存7天
self.release_lock(task_id)
# 使用示例
distributor = TaskDistributor()
# 分发任务
task = {'type': 'data_sync', 'params': {'table': 'users', 'date': '2024-01-15'}}
result = distributor.distribute_task(task)
print(result) # {'status': 'success', 'task_id': 'xxx', ...}
# 重复分发相同任务
result = distributor.distribute_task(task)
print(result) # {'status': 'duplicate', 'task_id': 'xxx', ...}
基于数据库的防重复方案
import sqlite3
import hashlib
import json
from datetime import datetime
from contextlib import contextmanager
class DatabaseTaskDistributor:
def __init__(self, db_path='tasks.db'):
self.db_path = db_path
self.init_database()
def init_database(self):
"""初始化数据库表"""
with self.get_connection() as conn:
conn.execute('''
CREATE TABLE IF NOT EXISTS tasks (
id INTEGER PRIMARY KEY AUTOINCREMENT,
task_hash TEXT UNIQUE NOT NULL,
task_data TEXT NOT NULL,
status TEXT DEFAULT 'pending',
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
completed_at TIMESTAMP,
worker_id TEXT
)
''')
conn.execute('''
CREATE INDEX IF NOT EXISTS idx_task_hash
ON tasks(task_hash)
''')
conn.execute('''
CREATE INDEX IF NOT EXISTS idx_status
ON tasks(status)
''')
@contextmanager
def get_connection(self):
"""获取数据库连接"""
conn = sqlite3.connect(self.db_path)
conn.row_factory = sqlite3.Row
try:
yield conn
conn.commit()
except Exception as e:
conn.rollback()
raise e
finally:
conn.close()
def _hash_task(self, task_data):
"""生成任务哈希"""
task_str = json.dumps(task_data, sort_keys=True)
return hashlib.sha256(task_str.encode()).hexdigest()
def distribute_task(self, task_data, worker_id=None):
"""分发任务(带防重复)"""
task_hash = self._hash_task(task_data)
with self.get_connection() as conn:
try:
cursor = conn.execute('''
INSERT INTO tasks (task_hash, task_data, worker_id)
VALUES (?, ?, ?)
''', (task_hash, json.dumps(task_data), worker_id))
return {
'status': 'success',
'task_id': cursor.lastrowid,
'task_hash': task_hash
}
except sqlite3.IntegrityError:
# 任务已存在
cursor = conn.execute('''
SELECT id, status, completed_at
FROM tasks
WHERE task_hash = ?
''', (task_hash,))
existing_task = cursor.fetchone()
return {
'status': 'duplicate',
'task_id': existing_task['id'],
'existing_status': existing_task['status'],
'completed_at': existing_task['completed_at']
}
def get_pending_tasks(self, limit=10):
"""获取待处理任务"""
with self.get_connection() as conn:
cursor = conn.execute('''
SELECT id, task_data, created_at
FROM tasks
WHERE status = 'pending'
ORDER BY created_at ASC
LIMIT ?
''', (limit,))
tasks = []
for row in cursor.fetchall():
tasks.append({
'id': row['id'],
'task_data': json.loads(row['task_data']),
'created_at': row['created_at']
})
return tasks
def mark_in_progress(self, task_id, worker_id):
"""标记任务进行中"""
with self.get_connection() as conn:
conn.execute('''
UPDATE tasks
SET status = 'in_progress', worker_id = ?
WHERE id = ? AND status = 'pending'
''', (worker_id, task_id))
return conn.rowcount > 0
def mark_completed(self, task_id):
"""标记任务完成"""
with self.get_connection() as conn:
conn.execute('''
UPDATE tasks
SET status = 'completed', completed_at = CURRENT_TIMESTAMP
WHERE id = ?
''', (task_id,))
# 使用示例
db_distributor = DatabaseTaskDistributor()
# 分发任务
task = {'type': 'email_send', 'to': 'user@example.com', 'template': 'welcome'}
result = db_distributor.distribute_task(task)
print(f"Task ID: {result['task_id']}, Status: {result['status']}")
# 获取待处理任务
pending_tasks = db_distributor.get_pending_tasks()
for task in pending_tasks:
print(f"Processing task {task['id']}")
# 处理任务...
db_distributor.mark_completed(task['id'])
基于文件系统的防重复方案
import os
import json
import hashlib
import threading
import time
from pathlib import Path
class FileBasedTaskDistributor:
def __init__(self, task_dir='./tasks'):
self.task_dir = Path(task_dir)
self.task_dir.mkdir(parents=True, exist_ok=True)
self.lock_dir = self.task_dir / 'locks'
self.lock_dir.mkdir(exist_ok=True)
self.completed_dir = self.task_dir / 'completed'
self.completed_dir.mkdir(exist_ok=True)
def _generate_task_name(self, task_data):
"""生成任务文件名"""
task_str = json.dumps(task_data, sort_keys=True)
task_hash = hashlib.md5(task_str.encode()).hexdigest()
return f"task_{task_hash}.json"
def _acquire_file_lock(self, task_name):
"""获取文件锁"""
lock_file = self.lock_dir / f"{task_name}.lock"
try:
# 尝试创建锁文件
fd = os.open(lock_file, os.O_CREAT | os.O_EXCL | os.O_WRONLY)
os.close(fd)
return True
except FileExistsError:
return False
def _release_file_lock(self, task_name):
"""释放文件锁"""
lock_file = self.lock_dir / f"{task_name}.lock"
try:
os.remove(lock_file)
except FileNotFoundError:
pass
def distribute_task(self, task_data):
"""分发任务"""
task_name = self._generate_task_name(task_data)
task_file = self.task_dir / task_name
# 检查是否已存在
if task_file.exists():
return {
'status': 'duplicate',
'task_name': task_name,
'message': '任务已存在'
}
# 检查是否已完成
completed_file = self.completed_dir / task_name
if completed_file.exists():
return {
'status': 'completed',
'task_name': task_name,
'message': '任务已完成'
}
# 尝试获取锁
if not self._acquire_file_lock(task_name):
return {
'status': 'locked',
'task_name': task_name,
'message': '任务正在处理中'
}
try:
# 写入任务文件
with open(task_file, 'w') as f:
json.dump({
'task_data': task_data,
'created_at': time.time(),
'status': 'pending'
}, f)
return {
'status': 'success',
'task_name': task_name,
'message': '任务分发成功'
}
finally:
self._release_file_lock(task_name)
def get_pending_tasks(self):
"""获取待处理任务"""
tasks = []
for task_file in self.task_dir.glob('task_*.json'):
with open(task_file, 'r') as f:
task_data = json.load(f)
if task_data.get('status') == 'pending':
tasks.append({
'file': task_file,
'data': task_data
})
return tasks
def mark_completed(self, task_name):
"""标记任务完成"""
task_file = self.task_dir / task_name
completed_file = self.completed_dir / task_name
if task_file.exists():
# 移动到completed目录
task_file.rename(completed_file)
return True
return False
# 使用示例
file_distributor = FileBasedTaskDistributor()
# 分发任务
task = {'type': 'report_generate', 'report_id': 'R123', 'format': 'pdf'}
result = file_distributor.distribute_task(task)
print(f"Status: {result['status']}")
# 获取待处理任务
pending = file_distributor.get_pending_tasks()
for task_info in pending:
print(f"Processing: {task_info['file']}")
# 处理任务...
file_distributor.mark_completed(task_info['file'].name)
分布式环境下的复杂防重复方案
import hashlib
import json
import time
from datetime import datetime, timedelta
class DistributedTaskManager:
def __init__(self, redis_client=None):
self.redis = redis_client
self.bloom_filter_key = "task:bloom_filter"
self.task_hash_key = "task:hash:{task_hash}"
self.task_timeout = 3600 # 1小时
def create_bloom_filter(self):
"""创建布隆过滤器"""
# 使用Redis的布隆过滤器模块
try:
self.redis.bf().create(self.bloom_filter_key, 0.01, 1000000)
except:
# 如果已存在,忽略
pass
def check_and_add_task(self, task_data, timeout=None):
"""检查并添加任务(防重复)"""
task_hash = self._generate_hash(task_data)
if timeout is None:
timeout = self.task_timeout
# 检查布隆过滤器
if self.redis.bf().exists(self.bloom_filter_key, task_hash):
# 进一步精确检查
task_key = self.task_hash_key.format(task_hash=task_hash)
if self.redis.exists(task_key):
return {
'status': 'duplicate',
'task_hash': task_hash,
'message': '任务已存在'
}
# 添加任务
pipeline = self.redis.pipeline()
pipeline.bf().add(self.bloom_filter_key, task_hash)
task_key = self.task_hash_key.format(task_hash=task_hash)
pipeline.setex(task_key, timeout, json.dumps(task_data))
pipeline.execute()
return {
'status': 'success',
'task_hash': task_hash,
'message': '任务添加成功'
}
def _generate_hash(self, task_data):
"""生成任务哈希"""
task_str = json.dumps(task_data, sort_keys=True)
return hashlib.sha256(task_str.encode()).hexdigest()
# 使用示例
manager = DistributedTaskManager(redis_client=redis.Redis())
manager.create_bloom_filter()
# 批量分发任务
tasks = [
{'type': 'sync', 'source': 'db1', 'target': 'db2'},
{'type': 'sync', 'source': 'db1', 'target': 'db2'}, # 重复
{'type': 'backup', 'source': 'db1'},
]
for task in tasks:
result = manager.check_and_add_task(task)
print(f"Task: {task}, Result: {result['status']}")
使用建议
选择策略
- Redis方案:适合高并发、分布式场景,性能最优
- 数据库方案:适合中小规模、需要持久化存储
- 文件方案:适合单机、简单部署场景
- 布隆过滤器方案:适合海量任务、内存敏感场景
最佳实践
# 组合使用多种防重复机制
class HybridTaskDistributor:
def __init__(self):
self.redis_distributor = TaskDistributor()
self.db_distributor = DatabaseTaskDistributor()
def distribute_with_guarantee(self, task_data):
"""带多重保障的任务分发"""
# 1. 首先尝试Redis(高性能)
result = self.redis_distributor.distribute_task(task_data)
if result['status'] == 'success':
# 2. 额外写入数据库(持久化保障)
db_result = self.db_distributor.distribute_task(task_data)
result['db_task_id'] = db_result.get('task_id')
return result
这个方案提供了多种防重复实现,你可以根据实际需求选择合适的方案。
版权声明:NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
足球直播
足球直播
足球直播
篮球直播
篮球直播
篮球直播
NBA直播
NBA直播
NBA直播
CBA直播
CBA直播
CBA直播
亚冠直播
亚冠直播
亚冠直播
欧冠直播
欧冠直播
欧冠直播
英超直播
英超直播
英超直播
西甲直播
西甲直播
西甲直播
中超直播
中超直播
中超直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
曼联直播
曼联直播
曼联直播
日职联直播
日职联直播
日职联直播
澳超直播
澳超直播
澳超直播
阿森纳直播
阿森纳直播
阿森纳直播
足球直播
足球直播
足球直播
NBA直播
NBA直播
NBA直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
欧冠直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
足球直播
足球直播
足球直播
足球直播
足球直播
英超直播
英超直播
英超直播
英超直播
英超直播
篮球直播
篮球直播
篮球直播
篮球直播
篮球直播
CBA直播
CBA直播
CBA直播
CBA直播
CBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
NBA直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播
中超直播