1
+ <?php
2
+ /**
3
+ * @author Stepan Zolotarev
4
+ */
5
+
6
+ declare (strict_types=1 );
7
+
8
+ namespace ServiceBus \Tests \Retry ;
9
+
10
+ use PHPUnit \Framework \TestCase ;
11
+ use ServiceBus \Common \EntryPoint \Retry \FailureContext ;
12
+ use ServiceBus \Common \Metadata \ServiceBusMetadata ;
13
+ use ServiceBus \MessageSerializer \Symfony \SymfonyJsonObjectSerializer ;
14
+ use ServiceBus \Retry \SimpleRetryStrategy ;
15
+ use ServiceBus \Storage \Common \DatabaseAdapter ;
16
+ use ServiceBus \Storage \Common \StorageConfiguration ;
17
+ use ServiceBus \Storage \Sql \DoctrineDBAL \DoctrineDBALAdapter ;
18
+ use ServiceBus \Storage \Sql \DoctrineDBAL \DoctrineDBALResultSet ;
19
+ use ServiceBus \Tests \EntryPoint \EntryPointTestMessage ;
20
+ use ServiceBus \Tests \TestContext ;
21
+
22
+ use function Amp \Promise \wait ;
23
+ use function ServiceBus \Common \uuid ;
24
+ use function ServiceBus \Storage \Sql \fetchOne ;
25
+
26
+ final class SimpleRetryStrategyTest extends TestCase
27
+ {
28
+ private DatabaseAdapter $ databaseAdapter ;
29
+ private SymfonyJsonObjectSerializer $ messageSerializer ;
30
+ private EntryPointTestMessage $ message ;
31
+ private TestContext $ context ;
32
+ private FailureContext $ failureContext ;
33
+
34
+ protected function setUp (): void
35
+ {
36
+ parent ::setUp ();
37
+
38
+ $ this ->databaseAdapter = new DoctrineDBALAdapter (
39
+ new StorageConfiguration ((string )\getenv ('TEST_POSTGRES_DSN ' ))
40
+ );
41
+
42
+ wait (
43
+ $ this ->databaseAdapter ->execute (
44
+ 'CREATE TABLE IF NOT EXISTS failed_messages
45
+ (
46
+ id uuid constraint failed_messages_pk primary key,
47
+ message_id uuid not null,
48
+ trace_id uuid not null,
49
+ message_hash varchar not null,
50
+ message_class varchar not null,
51
+ message_payload bytea not null,
52
+ failure_context jsonb not null,
53
+ recorded_at timestamp not null,
54
+ recovered_at timestamp
55
+ ); '
56
+ )
57
+ );
58
+
59
+ $ this ->messageSerializer = new SymfonyJsonObjectSerializer ();
60
+ $ this ->message = new EntryPointTestMessage (uuid ());
61
+ $ this ->context = new TestContext ($ this ->message );
62
+ $ this ->failureContext = new FailureContext ([$ this ->message ->id => 'some error ' ]);
63
+ }
64
+
65
+ /**
66
+ * @test
67
+ */
68
+ public function retry (): void
69
+ {
70
+ $ retryStrategy = new SimpleRetryStrategy (
71
+ databaseAdapter: $ this ->databaseAdapter ,
72
+ messageSerializer: $ this ->messageSerializer ,
73
+ maxRetryCount: 10 ,
74
+ retryDelay: 1
75
+ );
76
+
77
+ wait ($ retryStrategy ->retry ($ this ->message , $ this ->context , $ this ->failureContext ));
78
+
79
+ self ::assertCount (1 , $ this ->context ->messages );
80
+ foreach ($ this ->context ->messages as $ key => $ contextMessage ) {
81
+ self ::assertSame ($ this ->message , $ contextMessage );
82
+ self ::assertArrayHasKey ($ key , $ this ->context ->withMetadata );
83
+ self ::assertSame ([
84
+ ServiceBusMetadata::SERVICE_BUS_MESSAGE_RETRY_COUNT => 1 ,
85
+ ServiceBusMetadata::SERVICE_BUS_MESSAGE_FAILED_IN => $ this ->message ->id ,
86
+ ], $ this ->context ->withMetadata [$ key ]->variables ());
87
+ }
88
+
89
+ /** @var DoctrineDBALResultSet $resultSet */
90
+ $ resultSet = wait (
91
+ $ this ->databaseAdapter ->execute (
92
+ 'SELECT * FROM failed_messages WHERE message_id = ? AND trace_id = ? ' ,
93
+ [
94
+ $ this ->context ->metadata ()->messageId (),
95
+ $ this ->context ->metadata ()->traceId (),
96
+ ]
97
+ )
98
+ );
99
+ $ data = wait (fetchOne ($ resultSet ));
100
+
101
+ self ::assertNull ($ data );
102
+ }
103
+
104
+ /**
105
+ * @test
106
+ */
107
+ public function retryWithMaxRetriesReached (): void
108
+ {
109
+ $ retryStrategy = new SimpleRetryStrategy (
110
+ databaseAdapter: $ this ->databaseAdapter ,
111
+ messageSerializer: $ this ->messageSerializer ,
112
+ maxRetryCount: 0 ,
113
+ retryDelay: 1
114
+ );
115
+
116
+ wait ($ retryStrategy ->retry ($ this ->message , $ this ->context , $ this ->failureContext ));
117
+
118
+ self ::assertCount (0 , $ this ->context ->messages );
119
+
120
+ /** @var DoctrineDBALResultSet $resultSet */
121
+ $ resultSet = wait (
122
+ $ this ->databaseAdapter ->execute (
123
+ 'SELECT * FROM failed_messages WHERE message_id = ? AND trace_id = ? ' ,
124
+ [
125
+ $ this ->context ->metadata ()->messageId (),
126
+ $ this ->context ->metadata ()->traceId (),
127
+ ]
128
+ )
129
+ );
130
+ $ data = wait (fetchOne ($ resultSet ));
131
+
132
+ self ::assertIsArray ($ data );
133
+ self ::assertArrayHasKey ('message_class ' , $ data );
134
+ self ::assertSame ($ data ['message_class ' ], EntryPointTestMessage::class);
135
+ }
136
+
137
+ /**
138
+ * @test
139
+ */
140
+ public function backoff (): void
141
+ {
142
+ $ retryStrategy = new SimpleRetryStrategy (
143
+ databaseAdapter: $ this ->databaseAdapter ,
144
+ messageSerializer: $ this ->messageSerializer ,
145
+ maxRetryCount: 0 ,
146
+ retryDelay: 1
147
+ );
148
+
149
+ wait ($ retryStrategy ->backoff ($ this ->message , $ this ->context , $ this ->failureContext ));
150
+
151
+ /** @var DoctrineDBALResultSet $resultSet */
152
+ $ resultSet = wait (
153
+ $ this ->databaseAdapter ->execute (
154
+ 'SELECT * FROM failed_messages WHERE message_id = ? AND trace_id = ? ' ,
155
+ [
156
+ $ this ->context ->metadata ()->messageId (),
157
+ $ this ->context ->metadata ()->traceId (),
158
+ ]
159
+ )
160
+ );
161
+ $ data = wait (fetchOne ($ resultSet ));
162
+
163
+ self ::assertIsArray ($ data );
164
+ self ::assertArrayHasKey ('message_class ' , $ data );
165
+ self ::assertSame ($ data ['message_class ' ], EntryPointTestMessage::class);
166
+ }
167
+ }
0 commit comments