-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
Core - Cancel pending tasks when browser crashed or v8 context gets released #5145
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Core - Cancel pending tasks when browser crashed or v8 context gets released #5145
Conversation
WalkthroughThe changes introduce frame-scoped management and cancellation of pending JavaScript tasks within the browser integration. Task repositories are refactored to group tasks by frame identifier, and new APIs for canceling tasks per frame or globally are added. Error handling is improved to return faulted tasks instead of returning null pointers. New tests validate context lifecycle and cancellation on browser crashes, including repeated callback execution. Changes
Sequence Diagram(s)sequenceDiagram
participant Test as Test
participant Browser as ChromiumWebBrowser
participant Frame as CefFrameWrapper
participant Repo as PendingTaskRepository
participant Host as BrowserHost
Test->>Browser: EvaluateScriptAsync(...)
Browser->>Frame: EvaluateScriptAsync(...)
alt Browser host available
Frame->>Repo: CreatePendingTask(frameId, timeout)
Repo-->>Frame: TaskCompletionSource
Frame->>Host: Send script for evaluation
Host-->>Frame: Script result
Frame->>Repo: RemovePendingTask(frameId, taskId)
Repo-->>Frame: Complete Task
else Host not available
Frame-->>Test: Return faulted Task (InvalidOperationException)
end
sequenceDiagram
participant Browser as ChromiumWebBrowser
participant Repo as PendingTaskRepository
Browser->>Repo: CancelPendingTasks(frameId)
Repo->>Repo: Cancel all tasks for frameId
Repo-->>Browser: Tasks canceled
Estimated code review effort🎯 4 (Complex) | ⏱️ ~90 minutes Poem
Note ⚡️ Unit Test Generation is now available in beta!Learn more here, or try it out under "Finishing Touches" below. 📜 Recent review detailsConfiguration used: CodeRabbit UI 📒 Files selected for processing (8)
🚧 Files skipped from review as they are similar to previous changes (6)
🔇 Additional comments (12)
✨ Finishing Touches
🧪 Generate unit tests
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 1
🧹 Nitpick comments (1)
CefSharp.Test/Javascript/EvaluateScriptAsyncTests.cs (1)
68-83
: Consider reducing the loop sizes to make the test more practical.While the test correctly validates OOM cancellation behavior, the nested loops with 10M x 10M iterations creating 100M character strings could cause test instability or excessive runtime. Consider smaller values that still reliably trigger OOM.
- let array1 = []; - for (let i = 0; i < 10000000; i++) { - let array2 = []; - for (let j = 0; j < 10000000; j++) { - array2.push('a'.repeat(100000000)); - } - array1.push(array2); - } + let array1 = []; + for (let i = 0; i < 1000; i++) { + let array2 = []; + for (let j = 0; j < 1000; j++) { + array2.push('a'.repeat(10000000)); + } + array1.push(array2); + }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (7)
CefSharp.Core.Runtime/Internals/CefFrameWrapper.cpp
(1 hunks)CefSharp.Core.Runtime/Internals/ClientAdapter.cpp
(3 hunks)CefSharp.Core.Runtime/Internals/ClientAdapter.h
(2 hunks)CefSharp.Core.Runtime/Internals/JavascriptCallbackProxy.cpp
(1 hunks)CefSharp.Test/Javascript/EvaluateScriptAsyncTests.cs
(3 hunks)CefSharp/Internals/PendingTaskRepository.cs
(2 hunks)CefSharp/Internals/TaskExtensions.cs
(1 hunks)
🧠 Learnings (1)
CefSharp.Core.Runtime/Internals/CefFrameWrapper.cpp (1)
Learnt from: amaitland
PR: #4475
File: CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.cpp:147-154
Timestamp: 2025-05-10T23:58:24.668Z
Learning: The GetCache
method of the IJavaScriptObjectCache
implementation should never return null in its current implementation. Both the legacy and per-browser cache implementations guarantee a non-null return value, with the per-browser implementation returning an empty dictionary when no cache exists for a given browser ID.
🧬 Code Graph Analysis (3)
CefSharp.Core.Runtime/Internals/JavascriptCallbackProxy.cpp (3)
CefSharp.BrowserSubprocess.Core/CefBrowserWrapper.h (1)
CefBrowserWrapper
(27-75)CefSharp.Core.Runtime/Internals/StringUtils.h (1)
ToNative
(74-84)CefSharp.Core.Runtime/Internals/Serialization/Primitives.cpp (2)
SetInt64
(41-49)SetInt64
(41-41)
CefSharp.Core.Runtime/Internals/ClientAdapter.cpp (2)
CefSharp.Core.Runtime/Internals/CefRequestContextHandlerAdapter.cpp (1)
ToClr
(52-52)CefSharp.Core.Runtime/Internals/Serialization/Primitives.cpp (2)
GetInt64
(52-60)GetInt64
(52-52)
CefSharp.Core.Runtime/Internals/CefFrameWrapper.cpp (3)
CefSharp.BrowserSubprocess.Core/Wrapper/Browser.h (1)
Identifier
(109-112)CefSharp.Core.Runtime/Internals/CefBrowserWrapper.h (1)
Identifier
(117-120)CefSharp.Core.Runtime/Request.h (1)
Identifier
(69-69)
🧰 Additional context used
🧠 Learnings (1)
CefSharp.Core.Runtime/Internals/CefFrameWrapper.cpp (1)
Learnt from: amaitland
PR: #4475
File: CefSharp.BrowserSubprocess.Core/CefAppUnmanagedWrapper.cpp:147-154
Timestamp: 2025-05-10T23:58:24.668Z
Learning: The GetCache
method of the IJavaScriptObjectCache
implementation should never return null in its current implementation. Both the legacy and per-browser cache implementations guarantee a non-null return value, with the per-browser implementation returning an empty dictionary when no cache exists for a given browser ID.
🧬 Code Graph Analysis (3)
CefSharp.Core.Runtime/Internals/JavascriptCallbackProxy.cpp (3)
CefSharp.BrowserSubprocess.Core/CefBrowserWrapper.h (1)
CefBrowserWrapper
(27-75)CefSharp.Core.Runtime/Internals/StringUtils.h (1)
ToNative
(74-84)CefSharp.Core.Runtime/Internals/Serialization/Primitives.cpp (2)
SetInt64
(41-49)SetInt64
(41-41)
CefSharp.Core.Runtime/Internals/ClientAdapter.cpp (2)
CefSharp.Core.Runtime/Internals/CefRequestContextHandlerAdapter.cpp (1)
ToClr
(52-52)CefSharp.Core.Runtime/Internals/Serialization/Primitives.cpp (2)
GetInt64
(52-60)GetInt64
(52-52)
CefSharp.Core.Runtime/Internals/CefFrameWrapper.cpp (3)
CefSharp.BrowserSubprocess.Core/Wrapper/Browser.h (1)
Identifier
(109-112)CefSharp.Core.Runtime/Internals/CefBrowserWrapper.h (1)
Identifier
(117-120)CefSharp.Core.Runtime/Request.h (1)
Identifier
(69-69)
🔇 Additional comments (20)
CefSharp.Core.Runtime/Internals/ClientAdapter.h (2)
73-73
: Good change to cancel tasks before cleanup.The shift from direct deletion to explicit task cancellation aligns with the PR objective of properly canceling pending JavaScript tasks when the V8 context is released or the browser crashes.
82-82
: Appropriate nullification after task cancellation.Setting the pointer to
nullptr
after canceling tasks is consistent with the new lifecycle management approach.CefSharp/Internals/TaskExtensions.cs (1)
23-23
: Good simplification of cancellation logic.Relying directly on
TrySetCanceled()
return value is cleaner and more robust than the previous status check, as the method already handles the completed task scenario internally.CefSharp.Core.Runtime/Internals/CefFrameWrapper.cpp (2)
240-240
: Improved error handling with faulted Task.Returning a faulted
Task
instead ofnullptr
provides better error propagation and consistent API behavior when the browser host is unavailable.
248-248
: Frame-scoped task management implementation.Adding the
Identifier
parameter enables frame-scoped task management, which is essential for the PR objective of canceling pending tasks when V8 contexts are released.CefSharp.Core.Runtime/Internals/JavascriptCallbackProxy.cpp (2)
30-30
: Consistent error handling pattern.Returning a faulted
Task
instead of throwing an exception maintains consistency with the error handling pattern established inCefFrameWrapper::EvaluateScriptAsync
.
39-54
: Frame-scoped task management and improved logic flow.Moving the callback task creation and message construction inside the frame validity check ensures tasks are only created for valid frames, and the addition of
_callback->FrameId
parameter enables proper frame-scoped task tracking.CefSharp.Core.Runtime/Internals/ClientAdapter.cpp (4)
704-704
: Essential cleanup on render process termination.Canceling all pending tasks when the render process terminates ensures proper cleanup and prevents dangling tasks, which is a core objective of this PR.
387-389
: Frame-scoped task cancellation on context release.Extracting the frame ID and canceling frame-specific pending tasks when the V8 context is released is exactly what the PR aims to achieve - proper cleanup when contexts become invalid.
393-393
: Consistent use of extracted frame ID.Using the pre-extracted
frameId
variable maintains consistency and avoids redundant calls toStringUtils::ToClr(frame->GetIdentifier())
.
484-484
: Frame-aware task removal operations.Adding the
frameId
parameter to bothRemovePendingTask
andRemoveJavascriptCallbackPendingTask
calls enables proper frame-scoped task management, ensuring tasks are tracked and removed at the correct granularity.Also applies to: 492-493
CefSharp.Test/Javascript/EvaluateScriptAsyncTests.cs (3)
11-11
: LGTM!The using statement is appropriately added to support the new test methods.
30-66
: Well-structured test for V8 context lifecycle!The test comprehensively validates the frame-scoped task cancellation behavior across different V8 context states, which aligns perfectly with the PR objectives.
323-323
: Good formatting consistency fix.CefSharp/Internals/PendingTaskRepository.cs (6)
22-23
: Good refactoring to support frame-scoped task management.The new structure properly encapsulates tasks by frame ID, which aligns with the PR objective of canceling tasks when V8 context is released.
33-60
: Correctly implements frame-scoped task creation.The method properly handles both creating new frame repositories and adding tasks to existing ones, with appropriate framework-specific implementations.
69-94
: Consistent implementation for callback task creation.The method correctly maintains the separation between regular and callback tasks while implementing frame-scoped management.
107-120
: Proper implementation of frame-scoped task removal.
147-158
: Key implementation for frame-specific task cancellation.This method enables the core PR objective of canceling all pending tasks when a V8 context is released or frame is destroyed.
160-170
: Comprehensive global task cancellation.Properly handles cancellation of all pending tasks across all frames, which is essential for browser disposal scenarios.
✅ Build CefSharp 138.0.170-CI5314 completed (commit 22ab072d60 by @campersau) |
❌ Build CefSharp 138.0.170-CI5315 failed (commit 9f11b8c2ef by @campersau) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (2)
CefSharp.Test/Javascript/JavascriptCallbackTests.cs (2)
27-71
: Comprehensive test coverage for V8 context lifecycle management.This test effectively validates the key scenarios outlined in the PR objectives:
- Script evaluation failure before V8 context creation
- Successful callback execution after context availability
- Task cancellation on context changes and browser disposal
The test logic is sound and the resource management with
using
statements is appropriate.Consider these improvements for test robustness:
Timing dependency: The 1000ms timeout in promises could cause flakiness in CI environments. Consider using a shorter timeout or mocking time-sensitive operations.
Exception validation: Line 36 only checks the message prefix. Consider validating the specific exception type for better test precision:
-var withoutV8ContextException = await Assert.ThrowsAsync<Exception>(() => browser.EvaluateScriptAsync("(function() { return 1+1; })")); +var withoutV8ContextException = await Assert.ThrowsAsync<InvalidOperationException>(() => browser.EvaluateScriptAsync("(function() { return 1+1; })"));
73-87
: Excellent focused test for crash scenario validation.This test cleanly validates the critical crash scenario outlined in the PR objectives. The use of
chrome://crash
is the standard approach for simulating browser crashes in Chromium-based testing, and the assertion logic correctly expectsTaskCanceledException
.The test structure is well-organized and focused on a single concern.
Minor consideration for test reliability:
Similar to the previous test, the 1000ms timeout could potentially cause timing issues in slower CI environments, though it's likely sufficient for crash testing scenarios.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (2)
CefSharp.Test/Javascript/EvaluateScriptAsyncTests.cs
(3 hunks)CefSharp.Test/Javascript/JavascriptCallbackTests.cs
(2 hunks)
✅ Files skipped from review due to trivial changes (1)
- CefSharp.Test/Javascript/EvaluateScriptAsyncTests.cs
🔇 Additional comments (1)
CefSharp.Test/Javascript/JavascriptCallbackTests.cs (1)
9-9
: LGTM: Clean namespace addition for test support.The using statement is appropriately added to support the
CefExample.HelloWorldUrl
usage in the new test methods.
❌ Build CefSharp 138.0.170-CI5316 failed (commit f7a447f0e8 by @campersau) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actionable comments posted: 0
🧹 Nitpick comments (1)
CefSharp.Test/Javascript/JavascriptCallbackTests.cs (1)
27-77
: Comprehensive test coverage for V8 context lifecycle scenarios.This test method effectively validates the core functionality described in the PR objectives - canceling pending tasks when V8 context is released or browser is disposed. The test structure is well-organized and covers multiple scenarios:
- ✅ Script evaluation failure before V8 context creation
- ✅ Successful callback execution after context creation
- ✅ Task cancellation on V8 context change (reload)
- ✅ Task cancellation on browser disposal
The async/await patterns and exception assertions are correctly implemented.
However, consider these minor improvements:
- var callbackExecuteWithoutV8ContextException = await Assert.ThrowsAsync<Exception>(() => browser.EvaluateScriptAsync("(function() { return 1+1; })")); + var withoutContextException = await Assert.ThrowsAsync<Exception>(() => browser.EvaluateScriptAsync("(function() { return 1+1; })")); - Assert.StartsWith("Unable to execute javascript at this time", withoutV8ContextException.Message); + Assert.StartsWith("Unable to execute javascript at this time", withoutContextException.Message);The variable names could be more concise while maintaining clarity.
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (3)
CefSharp.Core.Runtime/Internals/JavascriptCallbackProxy.cpp
(1 hunks)CefSharp.Test/Javascript/EvaluateScriptAsyncTests.cs
(3 hunks)CefSharp.Test/Javascript/JavascriptCallbackTests.cs
(3 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
- CefSharp.Core.Runtime/Internals/JavascriptCallbackProxy.cpp
- CefSharp.Test/Javascript/EvaluateScriptAsyncTests.cs
🔇 Additional comments (3)
CefSharp.Test/Javascript/JavascriptCallbackTests.cs (3)
9-9
: LGTM: Import addition is appropriate.The
CefSharp.Example
import is correctly added and used in the test methods to accessCefExample.HelloWorldUrl
.
79-93
: Excellent test for browser crash scenario.This test method directly validates one of the core PR objectives - ensuring pending tasks are canceled when the browser crashes. The implementation is clean and effective:
- Uses
chrome://crash
to simulate browser crash condition- Properly tests that delayed promise callbacks are canceled
- Correctly expects
TaskCanceledException
The test aligns perfectly with the PR's goal of handling task cancellation during browser crashes.
306-322
: Good test coverage for repeated callback execution.This test method ensures that the refactored frame-scoped task management system maintains compatibility with existing callback behavior. The test validates that:
- Callbacks can be executed multiple times successfully
- Results remain consistent across executions
- No issues arise from the new task repository structure
The simple but effective test design provides confidence in the backwards compatibility of the changes.
❌ Build CefSharp 138.0.170-CI5317 failed (commit 284fd87c1c by @campersau) |
Thanks for the PR 👍 Any ideas what's causing the tests to fail when run on appveyor? |
I currently don't know, my run did work: https://ci.appveyor.com/project/campersau/cefsharp/builds/52449336 |
❌ Build CefSharp 138.0.330-CI5324 failed (commit 1606c8fea4 by @campersau) |
It looks like the same issue happens in main from time to time as well. E.g.: 633a8cd |
The GPU crash happens semi regularly, hopefully switching to The
I don't remember seeing this before, looking at a few other failed ones and it has happened prior, so maybe unrelated. |
I'd asked about the GCM errors at https://www.magpcss.org/ceforum/viewtopic.php?f=6&t=20318 Might have to follow up to see if there's anything further related to those. |
a942fc5
to
774abb1
Compare
I should be able to look at this over the weekend. |
✅ Build CefSharp 138.0.330-CI5327 completed (commit 6313f2f997 by @campersau) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Overall looks excellent! Thanks
Couple of minor things to discuss inline.
framePendingTasks.Clear(); | ||
} | ||
|
||
private sealed class FramePendingTaskRepository : IDisposable |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Class in own file please.
Probably worth generating a few simple test cases for this class
@@ -70,8 +70,7 @@ namespace CefSharp | |||
|
|||
CloseAllPopups(true); | |||
|
|||
//this will dispose the repository and cancel all pending tasks | |||
delete _pendingTaskRepository; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
delete
will call Dispose
if it's implemented. Guess it's semantics, might be worth having pending task repository implement IDisposable
.
@@ -23,6 +24,74 @@ public JavascriptCallbackTests(ITestOutputHelper output, CefSharpFixture collect | |||
this.collectionFixture = collectionFixture; | |||
} | |||
|
|||
[Fact] | |||
public async Task V8Context() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thoughts on a more descriptive name for this test?
@@ -26,6 +27,52 @@ public EvaluateScriptAsyncTests(ITestOutputHelper output, CefSharpFixture collec | |||
this.collectionFixture = collectionFixture; | |||
} | |||
|
|||
[Fact] | |||
public async Task V8Context() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thoughts on a more descriptive name for this test?
Fixes: #5144
Summary:
Changes:
How Has This Been Tested?
Unittest
Screenshots (if appropriate):
Types of changes
Checklist:
Summary by CodeRabbit
Bug Fixes
New Features
Tests
Refactor