fix: asyncio.Lock on channel create + PROJECT_NAME in .env.example
This commit is contained in:
@@ -10,5 +10,8 @@ BRAIN_PATH=C:\Users\Certes\.gemini\antigravity\brain
|
|||||||
# 세션 활성 판단: 마지막 파일 변경으로부터 이 시간(초) 이내면 활성
|
# 세션 활성 판단: 마지막 파일 변경으로부터 이 시간(초) 이내면 활성
|
||||||
ACTIVE_TIMEOUT_SECONDS=300
|
ACTIVE_TIMEOUT_SECONDS=300
|
||||||
|
|
||||||
|
# Project name (used for Discord channel: AG-{PROJECT_NAME})
|
||||||
|
PROJECT_NAME=gravity_control
|
||||||
|
|
||||||
# Watcher Settings
|
# Watcher Settings
|
||||||
DEBOUNCE_SECONDS=2
|
DEBOUNCE_SECONDS=2
|
||||||
|
|||||||
50
bot.py
50
bot.py
@@ -97,6 +97,7 @@ class GravityBot(commands.Bot):
|
|||||||
self.session_status_messages: dict[str, int] = {} # conv_id → msg_id
|
self.session_status_messages: dict[str, int] = {} # conv_id → msg_id
|
||||||
self._sent_approval_ids: set[str] = set()
|
self._sent_approval_ids: set[str] = set()
|
||||||
self._ready_event = asyncio.Event()
|
self._ready_event = asyncio.Event()
|
||||||
|
self._channel_lock = asyncio.Lock() # Prevents double-create race
|
||||||
self.bridge = BridgeProtocol()
|
self.bridge = BridgeProtocol()
|
||||||
self.session_category: discord.CategoryChannel | None = None
|
self.session_category: discord.CategoryChannel | None = None
|
||||||
self.guild: discord.Guild | None = None
|
self.guild: discord.Guild | None = None
|
||||||
@@ -187,33 +188,38 @@ class GravityBot(commands.Bot):
|
|||||||
async def _get_project_channel(self) -> discord.TextChannel:
|
async def _get_project_channel(self) -> discord.TextChannel:
|
||||||
"""Get the project channel. Create if it doesn't exist yet.
|
"""Get the project channel. Create if it doesn't exist yet.
|
||||||
|
|
||||||
Thread-safe: only ONE channel will ever be created because
|
Uses asyncio.Lock to prevent race between event processor
|
||||||
self.project_channel acts as a singleton guard.
|
and approval scanner both creating channels simultaneously.
|
||||||
"""
|
"""
|
||||||
if self.project_channel:
|
if self.project_channel:
|
||||||
return self.project_channel
|
return self.project_channel
|
||||||
|
|
||||||
# Create the channel
|
async with self._channel_lock:
|
||||||
try:
|
# Double-check after acquiring lock
|
||||||
self.project_channel = await self.guild.create_text_channel(
|
if self.project_channel:
|
||||||
name=self._channel_name,
|
return self.project_channel
|
||||||
category=self.session_category,
|
|
||||||
topic=f"Gravity Control — Antigravity Bridge",
|
|
||||||
)
|
|
||||||
logger.info(f"Created project channel: #{self._channel_name}")
|
|
||||||
|
|
||||||
embed = discord.Embed(
|
# Create the channel
|
||||||
title=f"🚀 {Config.PROJECT_NAME}",
|
try:
|
||||||
description=(
|
self.project_channel = await self.guild.create_text_channel(
|
||||||
f"Antigravity Bridge 연결됨\n"
|
name=self._channel_name,
|
||||||
f"모든 세션 이벤트가 이 채널로 전달됩니다."
|
category=self.session_category,
|
||||||
),
|
topic=f"Gravity Control — Antigravity Bridge",
|
||||||
color=discord.Color.blue(),
|
)
|
||||||
timestamp=datetime.now(timezone.utc),
|
logger.info(f"Created project channel: #{self._channel_name}")
|
||||||
)
|
|
||||||
await self.project_channel.send(embed=embed)
|
embed = discord.Embed(
|
||||||
except discord.errors.Forbidden:
|
title=f"🚀 {Config.PROJECT_NAME}",
|
||||||
logger.error(f"No permission to create channel: {self._channel_name}")
|
description=(
|
||||||
|
f"Antigravity Bridge 연결됨\n"
|
||||||
|
f"모든 세션 이벤트가 이 채널로 전달됩니다."
|
||||||
|
),
|
||||||
|
color=discord.Color.blue(),
|
||||||
|
timestamp=datetime.now(timezone.utc),
|
||||||
|
)
|
||||||
|
await self.project_channel.send(embed=embed)
|
||||||
|
except discord.errors.Forbidden:
|
||||||
|
logger.error(f"No permission to create channel: {self._channel_name}")
|
||||||
|
|
||||||
return self.project_channel
|
return self.project_channel
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user