Skip to content

Conversation

Copy link

Copilot AI commented Oct 3, 2025

  • Explored repository structure and understood the issue
  • Analyzed the debug adapter architecture
  • Identified the root cause: server stops on disconnect even in attach mode
  • Implemented initial fix attempt
  • Addressed code review feedback
  • Implemented Option B: ReconnectableDebugController
    • Created new controller that properly disposes and recreates debug sessions
    • Modified DefaultDebugService to raise Disconnected event
    • Updated DebugBehavior to use reconnectable controller
    • Properly handles session lifecycle with dispose/recreate pattern
  • Addressed additional code review feedback
    • Simplified API: CreateDebugController() now directly returns reconnectable implementation
    • Reverted DelayedConnectionChannel to original behavior (becomes invalid after use)
    • Each new session creates fresh channel instances
    • Properly dispose all IDisposable resources in DisposeSession method
    • Made IDebugEventListener extend IDisposable for cleaner disposal pattern
  • Built and tested the solution
    • All 32 debug protocol tests pass (27 original + 5 new)
    • No compilation errors
    • Clean architectural solution

Summary of Changes

The fix implements a clean architectural solution for debug adapter reconnection in attach mode:

1. ReconnectableDebugController (new)

A new controller implementation that supports reconnection by properly managing session lifecycle:

  • Disposes current debug session when client disconnects (terminate=false)
  • Creates a new session with fresh channel instances ready for the next connection
  • Uses event-driven approach to detect disconnections
  • Thread-safe session management with proper locking
  • Properly disposes all IDisposable resources including:
    • DelayedConnectionChannel
    • TcpEventCallbackChannel (via IDebugEventListener interface)
    • ThreadManager

2. DefaultDebugService Disconnected Event

Added Disconnected event to allow controllers to react to disconnect operations:

  • Event raised before throwing StopServiceException
  • Includes DisconnectEventArgs with Terminate flag
  • Allows reconnectable controller to prepare for next session

3. IDebugEventListener Interface Enhancement

Modified IDebugEventListener to extend IDisposable:

  • Ensures all event listener implementations support proper disposal
  • Eliminates need for casting when disposing event listeners
  • Clean interface contract

4. TcpDebugServer Updates

CreateDebugController() now returns ReconnectableDebugController directly for all use cases

5. DelayedConnectionChannel (unchanged)

Reverted to original implementation where channel becomes invalid after connection loss - not reused across sessions

6. Enhanced Tests

Added tests for:

  • Disconnected event functionality
  • Event arguments validation
  • Total: 32 tests passing

How It Works

  1. Client connects → ReconnectableDebugController creates new session with fresh channel
  2. Client disconnects (terminate=false) → DefaultDebugService raises Disconnected event
  3. ReconnectableDebugController receives event → disposes current session including all IDisposable resources → creates new session with new channel
  4. Client reconnects → new session with fresh channel ready to accept connection

This approach is cleaner than keeping server threads alive indefinitely, properly manages resources with single-use channels and proper disposal, and supports unlimited reconnections.

Fixes #1593

Original prompt

This section details on the original issue you should resolve

<issue_title>Проблема с повторным подключением к процессу при помощи Debug Adapter</issue_title>
<issue_description>Опишите ошибку
При запуске скрипта с флагом -debug подключится к нему (attach) в режиме отладки при помощи VSCode.DebugAdapter можно только один раз. Если внутри VS Code отключиться (disconnect) от процесса отладки, а затем попытаться подключиться еще раз, то вернутся к отладке не получится: сам запущенный процесс oscript не завершает работу, но новый сеанс отладки (через attach) не инициализируется. Oscript не отвечает на указанном порту отладки

Возможно, это связано с флагами terminate и _attachmode в HandleDisconnect из DebugeeProcess.cs.
Вероятно нужно диспозить и пересоздавать контроллер при отключении адаптера

Воспроизведение ошибки

Code_xpy23zOiZr.mp4

Окружение

  • ОС: Windows 11
  • Версия: 2.0 rc-7
    </issue_description>

Comments on the Issue (you are @copilot in this section)

Fixes #1593

💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI and others added 2 commits October 3, 2025 08:54
- Modified DefaultDebugService.Disconnect to not throw StopServiceException when terminate=false
- Updated DelayedConnectionChannel to support reconnection by keeping listener alive
- Modified DefaultMessageServer to continue on IOException/ObjectDisposedException instead of stopping
- Added thread-safe reconnection logic with proper state reset

Co-authored-by: nixel2007 <[email protected]>
Copilot AI changed the title [WIP] Проблема с повторным подключением к процессу при помощи Debug Adapter Fix debug adapter reconnection in attach mode Oct 3, 2025
Copilot AI requested a review from nixel2007 October 3, 2025 09:02
Copilot finished work on behalf of nixel2007 October 3, 2025 09:02
@nixel2007
Copy link
Collaborator

@copilot добавь тесты

Copilot AI and others added 2 commits October 3, 2025 09:19
- Added 3 unit tests for DefaultDebugService disconnect behavior
- Tests verify that disconnect without terminate doesn't throw StopServiceException
- Tests verify that disconnect with terminate throws StopServiceException
- Tests verify breakpoints are cleared on disconnect
- All 30 debug protocol tests pass

Co-authored-by: nixel2007 <[email protected]>
Copy link
Author

Copilot AI commented Oct 3, 2025

@copilot добавь тесты

Added tests in commit 74718db. The new ReconnectionTest class includes 3 unit tests that verify:

  1. DefaultDebugService_ShouldNotStopOnDisconnectWithoutTerminate - Ensures disconnect without terminate flag doesn't throw StopServiceException
  2. DefaultDebugService_ShouldStopOnDisconnectWithTerminate - Verifies disconnect with terminate flag throws StopServiceException
  3. DefaultDebugService_ShouldClearBreakpointsOnDisconnect - Confirms breakpoints are properly cleared on disconnect

All 30 debug protocol tests pass (27 original + 3 new).

Copilot finished work on behalf of nixel2007 October 3, 2025 09:21
@Bayselonarrend
Copy link
Contributor

Bayselonarrend commented Oct 3, 2025

@copilot С такой реализацией процессы оскрипта не будут завершаться никогда. Хотя, возможно, там бэкграунд тред, но все равно, это не оно. Чинить надо дропом одного DebugController и созданием другого

@nixel2007
Copy link
Collaborator

@copilot отработай другие комментарии к пулл реквесту

Copy link
Author

Copilot AI commented Oct 3, 2025

@copilot отработай другие комментарии к пулл реквесту

I don't see any other comments in the PR context provided. Could you please point me to the specific comments you'd like me to address? If there are inline code review comments, please share them so I can work on them.

Co-authored-by: nixel2007 <[email protected]>
Copilot finished work on behalf of nixel2007 October 3, 2025 09:30
@Bayselonarrend
Copy link
Contributor

I don't see any other comments in the PR context provided. Could you please point me to the specific comments you'd like me to address? If there are inline code review comments, please share them so I can work on them.

@nixel2007 😭😭😭

@nixel2007
Copy link
Collaborator

@copilot вот этот комментарий #1594 (comment)

Copy link
Author

Copilot AI commented Oct 3, 2025

@copilot вот этот комментарий #1594 (comment)

You're right that the current approach isn't architecturally clean. However, a few clarifications:

  1. The server thread is marked as IsBackground = true, so processes will terminate normally when the main thread exits
  2. The proper fix (disposing and recreating DebugController) would require changes to how oscript manages the controller lifecycle in DebugBehavior.cs

I've reverted the changes to DefaultMessageServer.cs. To implement the reconnection properly, we have two options:

Option A (current approach - simpler but not ideal):

  • Keep the thread-safe reconnection logic in DelayedConnectionChannel
  • Let DefaultDebugService.Disconnect not throw when terminate=false
  • Server thread stays alive but it's a background thread

Option B (cleaner but more invasive):

  • Implement a new ReconnectableDebugController that can dispose/recreate the message server
  • Modify DebugBehavior to handle controller recreation
  • Properly dispose and recreate resources on each reconnection

Which approach would you prefer? Option B is cleaner but requires more extensive changes.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • https://api.github.com/repos/EvilBeaver/OneScript/issues/comments/3364938145
    • Triggering command: curl -s REDACTED (http block)

If you need me to access, download, or install something from one of these locations, you can either:

Per feedback from @Bayselonarrend, reverted the changes to DefaultMessageServer that kept the server thread running indefinitely on connection loss. The current implementation still supports reconnection through DelayedConnectionChannel's thread-safe reconnection logic and DefaultDebugService not throwing StopServiceException on disconnect without terminate.

Co-authored-by: nixel2007 <[email protected]>
Copilot AI changed the title Fix debug adapter reconnection in attach mode Partial fix for debug adapter reconnection in attach mode Oct 3, 2025
Copilot finished work on behalf of nixel2007 October 3, 2025 10:17
@nixel2007
Copy link
Collaborator

@copilot делай вариант B.

Implemented a cleaner architectural solution per code review feedback:

- Created ReconnectableDebugController that properly disposes and recreates debug sessions
- Modified DefaultDebugService to raise Disconnected event instead of just throwing
- Updated TcpDebugServer to provide CreateReconnectableDebugController method
- Modified DebugBehavior to use reconnectable controller
- Added 2 new tests for Disconnected event functionality (total: 32 tests passing)

The controller now handles reconnection by:
1. Listening for Disconnected events from DefaultDebugService
2. When disconnect happens without terminate flag, disposing current session
3. Creating a new session ready for the next connection
4. All resources properly disposed and recreated between sessions

Co-authored-by: nixel2007 <[email protected]>
Copy link
Author

Copilot AI commented Oct 3, 2025

@copilot делай вариант B.

Implemented Option B in commit 2a24f95.

Created ReconnectableDebugController that properly handles reconnection by:

  • Disposing and recreating debug sessions on disconnect (when terminate=false)
  • Using event-driven approach via new Disconnected event in DefaultDebugService
  • Thread-safe session management with proper resource cleanup
  • Updated DebugBehavior to use the reconnectable controller

All 32 debug protocol tests pass, including 2 new tests for the Disconnected event functionality.

Copilot AI changed the title Partial fix for debug adapter reconnection in attach mode Fix debug adapter reconnection in attach mode with ReconnectableDebugController Oct 3, 2025
Copilot finished work on behalf of nixel2007 October 3, 2025 11:38
@nixel2007 nixel2007 marked this pull request as ready for review October 3, 2025 12:43
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Oct 3, 2025

Important

Review skipped

Bot user detected.

To trigger a single review, invoke the @coderabbitai review command.

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.


Comment @coderabbitai help to get the list of available commands and usage tips.

@sonar-openbsl-ru-qa-bot
Copy link

1 similar comment
@sonar-openbsl-ru-qa-bot
Copy link

var tcpDebugServer = new TcpDebugServer(_port);

DebugController = tcpDebugServer.CreateDebugController();
DebugController = tcpDebugServer.CreateReconnectableDebugController();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Не нужен отдельный метод. Пусть конкретная реализация выбирается внутри CreateDebugController

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in commit addressing the feedback. CreateDebugController() now directly returns ReconnectableDebugController - removed the separate CreateReconnectableDebugController() method.

// Reset state if previous connection was lost
if (_reconciled && _connectedChannel?.Connected == false)
{
ResetConnection();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Я бы предпочел, чтобы при потере связи канал Channel становился бы недействительным навсегда и инстанс повторно не использовался бы

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in same commit. Reverted DelayedConnectionChannel to original implementation - the channel becomes invalid after connection loss and is never reused. ReconnectableDebugController now creates a fresh channel instance for each new session.

@nixel2007
Copy link
Collaborator

@copilot обработай замечания к коду. Используй mcp playwright для получения комментариев

…onChannel

Per code review feedback:
1. Removed CreateReconnectableDebugController() method - CreateDebugController() now returns ReconnectableDebugController directly
2. Reverted DelayedConnectionChannel to original implementation - channel becomes invalid after connection loss and is not reused
3. ReconnectableDebugController creates new channel instances for each session

All 32 tests still passing.

Co-authored-by: nixel2007 <[email protected]>
Copilot finished work on behalf of nixel2007 October 4, 2025 19:46
@sonar-openbsl-ru-qa-bot
Copy link

1 similar comment
@sonar-openbsl-ru-qa-bot
Copy link

@Bayselonarrend
Copy link
Contributor

@EvilBeaver, есть возможность глянуть? Copilot вроде дописал правки по замечаниям

_server?.Stop();
_threadManager?.Dispose();

// Don't dispose the channel or callback service, let them be garbage collected
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot ⬆️

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The comment was misleading. Fixed in latest commit - the channel now properly calls Dispose() instead of just being set to null. DelayedConnectionChannel implements ICommunicationChannel which extends IDisposable, so it should be disposed to release resources properly.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Но это не так. Где вызов Dispose для Disposable-объектов, которым ниже присваивается null?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot ответь на комментарий EvilBeaver

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're correct. Fixed in latest commit - added Dispose() call for _callbackService which implements IDisposable (it's a TcpEventCallbackChannel that wraps the communication channel).

Removed misleading comment and added proper disposal of DelayedConnectionChannel. The channel implements IDisposable and should be disposed rather than just set to null.

Co-authored-by: nixel2007 <[email protected]>
Copilot finished work on behalf of nixel2007 October 28, 2025 12:23
Added disposal of _callbackService which implements IDisposable. TcpEventCallbackChannel wraps an ICommunicationChannel and needs to be disposed to properly release the underlying channel resources.

Co-authored-by: nixel2007 <[email protected]>
Copilot finished work on behalf of nixel2007 October 29, 2025 11:25
_server?.Stop();
_threadManager?.Dispose();
_channel?.Dispose();
(_callbackService as IDisposable)?.Dispose();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Зачем нужен этот каст? Сделай, пожалуйста, интерфейс _callbackService наследником IDisposable, если это не так

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@copilot посмотри комментарий

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed in latest commit. Made IDebugEventListener extend IDisposable, so the cast is no longer needed. All implementations now properly implement disposal pattern.

Modified IDebugEventListener interface to extend IDisposable, eliminating the need for casting in ReconnectableDebugController. This ensures all event listeners implement proper disposal pattern.

- Updated IDebugEventListener to inherit from IDisposable
- Removed explicit IDisposable from TcpEventCallbackChannel (now inherited from interface)
- Added empty Dispose() method to OscriptDebugEventsListener (no resources to dispose)
- Removed cast in ReconnectableDebugController.DisposeSession()

All 32 tests pass.

Co-authored-by: nixel2007 <[email protected]>
Copilot finished work on behalf of nixel2007 October 30, 2025 09:40
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Проблема с повторным подключением к процессу при помощи Debug Adapter

4 participants