Skip to content

Commit d940b46

Browse files
authored
Fixed dispose of chrome processes
Fixed dispose of chrome processes
2 parents 667c5f7 + 4d5f8e4 commit d940b46

File tree

9 files changed

+113
-32
lines changed

9 files changed

+113
-32
lines changed

.github/dependabot.yml

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
1-
# To get started with Dependabot version updates, you'll need to specify which
2-
# package ecosystems to update and where the package manifests are located.
3-
# Please see the documentation for all configuration options:
4-
# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
5-
61
version: 2
72
updates:
83
- package-ecosystem: "nuget" # See documentation for possible values
94
directory: "/" # Location of package manifests
105
schedule:
116
interval: "daily"
7+
ignore:
8+
- dependency-name: "nunit"
9+
- dependency-name: "SonarAnalyzer.CSharp"
10+
- dependency-name: "AngleSharp"
11+
- dependency-name: "Microsoft.NET.Test.Sdk"
12+
- dependency-name: "Microsoft.AspNetCore.Mvc.Testing"
13+
- dependency-name: "Moq"
14+
- dependency-name: "xunit"
15+
- dependency-name: "xunit.runner.visualstudio"
16+
- dependency-name: "MSTest.TestAdapter"
17+
- dependency-name: "ImageSharpCompare"
18+
- dependency-name: "PdfjsSharp"

PuppeteerSharp.Renderer/PuppeteerSharp.Renderer.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
2525
<PublishRepositoryUrl>true</PublishRepositoryUrl>
2626
<EmbedUntrackedSources>true</EmbedUntrackedSources>
27-
<LangVersion>8.0</LangVersion>
27+
<LangVersion>9.0</LangVersion>
2828
<Nullable>enable</Nullable>
2929
<PackageId>PuppeteerSharp.Renderer</PackageId>
3030
<Product>PuppeteerSharp.Renderer</Product>
@@ -36,7 +36,7 @@
3636
<ItemGroup>
3737
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="all" />
3838
<PackageReference Include="PuppeteerSharp" Version="4.0.0" />
39-
<PackageReference Include="SonarAnalyzer.CSharp" Version="8.21.0.30542">
39+
<PackageReference Include="SonarAnalyzer.CSharp" Version="8.22.0.31243">
4040
<PrivateAssets>all</PrivateAssets>
4141
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
4242
</PackageReference>

PuppeteerSharp.Renderer/Renderer.cs

Lines changed: 45 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,13 @@ namespace Codeuctivity.PuppeteerSharp
99
/// <summary>
1010
/// Renders HTML files
1111
/// </summary>
12-
public class Renderer : IAsyncDisposable
12+
public class Renderer : IAsyncDisposable, IDisposable
1313
{
1414
private Browser Browser { get; set; } = default!;
1515
private int LastProgressValue { get; set; }
1616

1717
/// <summary>
18-
/// Browserfetcher - used to get chromium bins
18+
/// Browser fetcher - used to get chromium bins
1919
/// </summary>
2020
public BrowserFetcher BrowserFetcher { get; private set; } = default!;
2121

@@ -54,7 +54,6 @@ private async Task<Renderer> InitializeAsync(BrowserFetcher browserFetcher)
5454
/// </summary>
5555
/// <param name="sourceHtmlFilePath"></param>
5656
/// <param name="destinationPdfFilePath"></param>
57-
/// <returns></returns>
5857
public async Task ConvertHtmlToPdf(string sourceHtmlFilePath, string destinationPdfFilePath)
5958
{
6059
if (!File.Exists(sourceHtmlFilePath))
@@ -63,7 +62,7 @@ public async Task ConvertHtmlToPdf(string sourceHtmlFilePath, string destination
6362
}
6463

6564
var absolutePath = Path.GetFullPath(sourceHtmlFilePath);
66-
var page = await Browser.NewPageAsync().ConfigureAwait(false);
65+
await using var page = await Browser.NewPageAsync().ConfigureAwait(false);
6766
await page.GoToAsync($"file://{absolutePath}").ConfigureAwait(false);
6867
await page.PdfAsync(destinationPdfFilePath).ConfigureAwait(false);
6968
}
@@ -73,7 +72,6 @@ public async Task ConvertHtmlToPdf(string sourceHtmlFilePath, string destination
7372
/// </summary>
7473
/// <param name="sourceHtmlFilePath"></param>
7574
/// <param name="destinationPngFilePath"></param>
76-
/// <returns></returns>
7775
public async Task ConvertHtmlToPng(string sourceHtmlFilePath, string destinationPngFilePath)
7876
{
7977
if (!File.Exists(sourceHtmlFilePath))
@@ -82,9 +80,9 @@ public async Task ConvertHtmlToPng(string sourceHtmlFilePath, string destination
8280
}
8381

8482
var absolutePath = Path.GetFullPath(sourceHtmlFilePath);
85-
var page = await Browser.NewPageAsync().ConfigureAwait(false);
83+
await using var page = await Browser.NewPageAsync().ConfigureAwait(false);
8684
await page.GoToAsync($"file://{absolutePath}").ConfigureAwait(false);
87-
await page.ScreenshotAsync(destinationPngFilePath, new ScreenshotOptions() { FullPage = true }).ConfigureAwait(false);
85+
await page.ScreenshotAsync(destinationPngFilePath, new ScreenshotOptions { FullPage = true }).ConfigureAwait(false);
8886
}
8987

9088
private void DownloadProgressChanged(object sender, DownloadProgressChangedEventArgs e)
@@ -95,15 +93,50 @@ private void DownloadProgressChanged(object sender, DownloadProgressChangedEvent
9593
}
9694
}
9795

98-
ValueTask IAsyncDisposable.DisposeAsync()
96+
/// <summary>
97+
/// Dispose
98+
/// </summary>
99+
public void Dispose()
100+
{
101+
Dispose(disposing: true);
102+
GC.SuppressFinalize(this);
103+
}
104+
105+
/// <summary>
106+
/// DisposeAsync
107+
/// </summary>
108+
public async ValueTask DisposeAsync()
99109
{
100-
if (Browser == null)
110+
await DisposeAsyncCore();
111+
112+
Dispose(disposing: false);
113+
#pragma warning disable CA1816 // Dispose methods should call SuppressFinalize
114+
GC.SuppressFinalize(this);
115+
#pragma warning restore CA1816 // Dispose methods should call SuppressFinalize
116+
}
117+
118+
/// <summary>
119+
/// Dispose
120+
/// </summary>
121+
/// <param name="disposing"></param>
122+
protected virtual void Dispose(bool disposing)
123+
{
124+
if (disposing)
101125
{
102-
return new ValueTask();
126+
Browser?.Dispose();
103127
}
128+
}
104129

105-
Browser.CloseAsync().ConfigureAwait(false);
106-
return ((IAsyncDisposable)Browser).DisposeAsync();
130+
/// <summary>
131+
/// DisposeAsync
132+
/// </summary>
133+
protected virtual async ValueTask DisposeAsyncCore()
134+
{
135+
if (Browser is not null)
136+
{
137+
await Browser.CloseAsync();
138+
await Browser.DisposeAsync();
139+
}
107140
}
108141
}
109142
}

PuppeteerSharp.RendererCliTests/PuppeteerSharp.RendererCliTests.csproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,10 @@
88

99
<ItemGroup>
1010
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.9.4" />
11+
<PackageReference Include="SonarAnalyzer.CSharp" Version="8.22.0.31243">
12+
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
13+
<PrivateAssets>all</PrivateAssets>
14+
</PackageReference>
1115
<PackageReference Include="xunit" Version="2.4.1" />
1216
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
1317
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>

PuppeteerSharp.RendererCliTests/RendererCliTests.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ public class RendererCliTests
1111
[Fact]
1212
public void VersionShouldBeProcessed()
1313
{
14-
Version.TryParse(Program.Version.ToString(), out _);
14+
var success = Version.TryParse(Program.Version.ToString(), out _);
15+
Assert.True(success);
1516
}
1617

1718
[Fact]
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
using System.Diagnostics;
2+
using System.Linq;
3+
using System.Threading.Tasks;
4+
using Xunit;
5+
6+
namespace PuppeteerSharp.RendererTests.Infrastrukture
7+
{
8+
public static class ChromiumProcessDisposedAsserter
9+
{
10+
public static async Task AssertNoChromeProcessIsRunning()
11+
{
12+
for (var i = 0; i < 20 && CountChromiumTasks() > 0; i++)
13+
{
14+
await Task.Delay(200);
15+
}
16+
Assert.Equal(0, CountChromiumTasks());
17+
}
18+
19+
public static int CountChromiumTasks()
20+
{
21+
var processes = Process.GetProcesses().Where(process => process.ProcessName.Contains("chrome")).ToList();
22+
return processes.Count;
23+
}
24+
}
25+
}

PuppeteerSharp.RendererTests/DocumentAsserter.cs renamed to PuppeteerSharp.RendererTests/Infrastrukture/DocumentAsserter.cs

File renamed without changes.

PuppeteerSharp.RendererTests/PuppeteerSharp.RendererTests.csproj

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
<PropertyGroup>
44
<TargetFrameworks>net5.0</TargetFrameworks>
55
<IsPackable>false</IsPackable>
6-
<LangVersion>8.0</LangVersion>
6+
<LangVersion>9.0</LangVersion>
77
<Nullable>enable</Nullable>
88
<IsPackable>false</IsPackable>
99
<EnableNETAnalyzers>true</EnableNETAnalyzers>
@@ -18,7 +18,7 @@
1818
<ItemGroup>
1919
<PackageReference Include="ImageSharpCompare" Version="1.1.34" />
2020
<PackageReference Include="PdfjsSharp" Version="1.0.50" />
21-
<PackageReference Include="SonarAnalyzer.CSharp" Version="8.21.0.30542">
21+
<PackageReference Include="SonarAnalyzer.CSharp" Version="8.22.0.31243">
2222
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
2323
<PrivateAssets>all</PrivateAssets>
2424
</PackageReference>

PuppeteerSharp.RendererTests/RendererTests.cs

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using Codeuctivity.PdfjsSharp;
22
using Codeuctivity.PuppeteerSharp;
3+
using PuppeteerSharp.RendererTests.Infrastrukture;
34
using System.IO;
45
using System.Linq;
56
using System.Threading.Tasks;
@@ -22,16 +23,19 @@ public async Task ShouldConvertHtmlToPdf(string testFileName)
2223
File.Delete(actualFilePath);
2324
}
2425

25-
await using var chromiumRenderer = await Renderer.CreateAsync();
26-
await chromiumRenderer.ConvertHtmlToPdf(sourceHtmlFilePath, actualFilePath);
26+
await using (var chromiumRenderer = await Renderer.CreateAsync())
27+
{
28+
await chromiumRenderer.ConvertHtmlToPdf(sourceHtmlFilePath, actualFilePath);
2729

28-
var actualImagePathDirectory = Path.Combine(Path.GetTempPath(), testFileName);
30+
var actualImagePathDirectory = Path.Combine(Path.GetTempPath(), testFileName);
2931

30-
using var rasterize = new Rasterizer();
31-
var actualImages = await rasterize.ConvertToPngAsync(actualFilePath, actualImagePathDirectory);
32+
using var rasterize = new Rasterizer();
33+
var actualImages = await rasterize.ConvertToPngAsync(actualFilePath, actualImagePathDirectory);
3234

33-
Assert.Single(actualImages);
34-
DocumentAsserter.AssertImageIsEqual(actualImages.Single(), expectReferenceFilePath, 50);
35+
Assert.Single(actualImages);
36+
DocumentAsserter.AssertImageIsEqual(actualImages.Single(), expectReferenceFilePath, 50);
37+
}
38+
await ChromiumProcessDisposedAsserter.AssertNoChromeProcessIsRunning();
3539
}
3640

3741
[Theory]
@@ -47,20 +51,27 @@ public async Task ShouldConvertHtmlToPng(string testFileName)
4751
File.Delete(actualFilePath);
4852
}
4953

50-
await using var chromiumRenderer = await Renderer.CreateAsync();
54+
await using (var chromiumRenderer = await Renderer.CreateAsync())
55+
{
56+
await chromiumRenderer.ConvertHtmlToPng(sourceHtmlFilePath, actualFilePath);
5157

52-
await chromiumRenderer.ConvertHtmlToPng(sourceHtmlFilePath, actualFilePath);
58+
DocumentAsserter.AssertImageIsEqual(actualFilePath, expectReferenceFilePath, 3500);
59+
}
5360

54-
DocumentAsserter.AssertImageIsEqual(actualFilePath, expectReferenceFilePath, 3100);
61+
await ChromiumProcessDisposedAsserter.AssertNoChromeProcessIsRunning();
5562
}
5663

5764
[Fact]
5865
public async Task ShouldDisposeGracefull()
5966
{
67+
var initialChromiumTasks = ChromiumProcessDisposedAsserter.CountChromiumTasks();
68+
6069
await using (var chromiumRenderer = new Renderer())
6170
{
6271
Assert.Null(chromiumRenderer.BrowserFetcher);
6372
}
73+
var afterDisposeChromiumTasks = ChromiumProcessDisposedAsserter.CountChromiumTasks();
74+
Assert.Equal(afterDisposeChromiumTasks, initialChromiumTasks);
6475
}
6576
}
6677
}

0 commit comments

Comments
 (0)