1
+ //-----------------------------------------------------------------------
2
+ // <copyright file="BugFix6948Spec.cs" company="Akka.NET Project">
3
+ // Copyright (C) 2009-2023 Lightbend Inc. <http://www.lightbend.com>
4
+ // Copyright (C) 2013-2023 .NET Foundation <https://github.com/akkadotnet/akka.net>
5
+ // </copyright>
6
+ //-----------------------------------------------------------------------
7
+
8
+ using System ;
9
+ using System . Collections . Generic ;
10
+ using System . Linq ;
11
+ using System . Threading . Tasks ;
12
+ using Akka . Actor ;
13
+ using Akka . Event ;
14
+ using Akka . TestKit ;
15
+ using FluentAssertions ;
16
+ using FluentAssertions . Extensions ;
17
+ using Xunit ;
18
+ using Xunit . Abstractions ;
19
+
20
+ namespace Akka . Tests . Actor ;
21
+
22
+ public class BugFix6948Spec : AkkaSpec
23
+ {
24
+ public BugFix6948Spec ( ITestOutputHelper output ) : base ( "akka.loglevel=DEBUG" , output )
25
+ {
26
+ }
27
+
28
+ [ Fact ( DisplayName = "#6948 ActorSystem should terminate cleanly on fatal exceptions" ) ]
29
+ public async Task ActorSystem_ShouldTerminateCleanlyOnOOM ( )
30
+ {
31
+ var actor = Sys . ActorOf ( Props . Create ( ( ) => new OutOfMemoryActor ( ) ) ) ;
32
+ actor . Tell ( "die" ) ;
33
+ ExpectMsg ( "dead" ) ;
34
+
35
+ var shutdown = CoordinatedShutdown . Get ( Sys ) ;
36
+ shutdown . AddTask ( CoordinatedShutdown . PhaseBeforeActorSystemTerminate , "z" , ( ) =>
37
+ {
38
+ var pressure = new List < long > ( ) ;
39
+ try
40
+ {
41
+ foreach ( var i in Enumerable . Range ( 0 , 50_000_000 ) )
42
+ {
43
+ pressure . Add ( i ) ;
44
+ }
45
+ }
46
+ catch ( OutOfMemoryException ex )
47
+ {
48
+ Log . Error ( ex , "I died (CoordinatedShutdown)" ) ;
49
+ throw ;
50
+ }
51
+
52
+ return Task . FromResult ( Done . Instance ) ;
53
+ } ) ;
54
+
55
+ var terminated = false ;
56
+ Sys . RegisterOnTermination ( ( ) =>
57
+ {
58
+ terminated = true ;
59
+ } ) ;
60
+
61
+ await shutdown . Run ( CoordinatedShutdown . UnknownReason . Instance ) ;
62
+ await Sys . Terminate ( ) . WaitAsync ( 5 . Seconds ( ) ) ;
63
+ terminated . Should ( ) . BeTrue ( ) ;
64
+ }
65
+
66
+ private class OutOfMemoryActor : ReceiveActor
67
+ {
68
+ private readonly List < long > _memoryPressure = new ( ) ;
69
+
70
+ public OutOfMemoryActor ( )
71
+ {
72
+ var log = Context . GetLogger ( ) ;
73
+
74
+ Receive < string > ( _ =>
75
+ {
76
+ try
77
+ {
78
+ foreach ( var i in Enumerable . Range ( 0 , 50_000_000 ) )
79
+ {
80
+ _memoryPressure . Add ( i ) ;
81
+ }
82
+ }
83
+ catch ( OutOfMemoryException e )
84
+ {
85
+ log . Error ( e , "I died (Actor)" ) ;
86
+ Sender . Tell ( "dead" ) ;
87
+ }
88
+ } ) ;
89
+ }
90
+ }
91
+ }
0 commit comments