Skip to content

Commit

Permalink
Merge pull request #7 from Local-Connectivity-Lab/ticket-481
Browse files Browse the repository at this point in the history
Adding thread lock, and related test
  • Loading branch information
philion authored Feb 20, 2024
2 parents ff0fc28 + cc4416c commit 10b624f
Show file tree
Hide file tree
Showing 4 changed files with 25 additions and 10 deletions.
12 changes: 8 additions & 4 deletions cog_scn.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@
from discord.commands import SlashCommandGroup
from discord.ext import commands, tasks

from netbot import NetbotException


log = logging.getLogger(__name__)

Expand Down Expand Up @@ -58,11 +60,13 @@ async def sync_thread(self, thread:discord.Thread):
ticket_id = self.bot.parse_thread_title(thread.name)
ticket = self.redmine.get_ticket(ticket_id, include_journals=True)
if ticket:
await self.bot.synchronize_ticket(ticket, thread)
return ticket
else:
return None
completed = await self.bot.synchronize_ticket(ticket, thread)
if completed:
return ticket
else:
raise NetbotException(f"Ticket {ticket.id} is locked for syncronization.")

return None


@tasks.loop(minutes=1.0) # FIXME to 5.0 minutes. set to 1 min for testing
Expand Down
10 changes: 8 additions & 2 deletions netbot.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@

log = logging.getLogger(__name__)

class NetbotException(Exception):
"""netbot exception"""


class NetBot(commands.Bot):
"""netbot"""
Expand Down Expand Up @@ -92,9 +95,10 @@ def format_redmine_note(self, message: discord.Message):
return f'"Discord":{message.jump_url}: {message.content}' # NOTE: message.clean_content


async def synchronize_ticket(self, ticket, thread:discord.Thread):
async def synchronize_ticket(self, ticket, thread:discord.Thread) -> bool:
"""
Synchronize a ticket to a thread
returns True after a sucessful sync or if there are no changes, false if a sync is in progress.
"""
# as this is an async method call, and we don't want to lock bot-level event processing,
# we need to create a per-ticket lock to make sure the same
Expand All @@ -107,7 +111,7 @@ async def synchronize_ticket(self, ticket, thread:discord.Thread):
async with self.lock:
if ticket.id in self.ticket_locks:
log.debug(f"ticket #{ticket.id} locked, skipping")
return
return False # locked
else:
# create lock flag
self.ticket_locks[ticket.id] = True
Expand Down Expand Up @@ -153,8 +157,10 @@ async def synchronize_ticket(self, ticket, thread:discord.Thread):
del self.ticket_locks[ticket.id]

log.info(f"DONE sync {ticket.id} <-> {thread.name}, took {synctime.age_str(sync_start)}")
return True # processed as expected
else:
log.debug(f"empty sync_rec for channel={thread.id}, assuming mismatch and skipping")
return False # not found


async def on_application_command_error(self, context: discord.ApplicationContext,
Expand Down
2 changes: 1 addition & 1 deletion redmine.py
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ def find_discord_user(self, discord_user_id:str):
def get_ticket(self, ticket_id:int, include_journals:bool = False):
"""get a ticket by ID"""
if ticket_id is None or ticket_id == 0:
log.warning(f"Invalid ticket number: {ticket_id}")
log.debug(f"Invalid ticket number: {ticket_id}")
return None

query = f"/issues/{ticket_id}.json"
Expand Down
11 changes: 8 additions & 3 deletions test_cog_scn.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,17 +82,22 @@ async def test_team_join_leave(self):


async def test_thread_sync(self):
test_ticket = 218
subject = f"Test Sync Ticket {self.tag}"
text = f"This is a test sync ticket tagged with {self.tag}."
ticket = self.redmine.create_ticket(self.user, subject, text)

ctx = self.build_context()
ctx.channel = unittest.mock.AsyncMock(discord.Thread)
ctx.channel.name = f"Ticket #{test_ticket}"
ctx.channel.name = f"Ticket #{ticket.id}"
#ctx.channel.id = 4321

await self.cog.sync(ctx)
ctx.respond.assert_called_with(f"SYNC ticket {test_ticket} to thread: {ctx.channel.name} complete")
ctx.respond.assert_called_with(f"SYNC ticket {ticket.id} to thread: {ctx.channel.name} complete")
# check for actual changes! updated timestamp!

# cleanup
self.redmine.remove_ticket(ticket.id)


if __name__ == '__main__':
# when running this main, turn on DEBUG
Expand Down

0 comments on commit 10b624f

Please sign in to comment.