@@ -7,9 +7,9 @@ use graph::{
7
7
prometheus:: { CounterVec , GaugeVec } ,
8
8
util:: timed_rw_lock:: TimedRwLock ,
9
9
} ;
10
- use std:: str:: FromStr ;
11
- use std:: sync:: Arc ;
10
+ use std:: sync:: { atomic:: AtomicBool , Arc } ;
12
11
use std:: { collections:: BTreeMap , time:: Duration } ;
12
+ use std:: { str:: FromStr , sync:: atomic} ;
13
13
14
14
use lazy_static:: lazy_static;
15
15
@@ -38,16 +38,20 @@ lazy_static! {
38
38
}
39
39
40
40
struct Watcher {
41
- sender : watch:: Sender < ( ) > ,
41
+ sender : Arc < watch:: Sender < ( ) > > ,
42
42
receiver : watch:: Receiver < ( ) > ,
43
43
}
44
44
45
45
impl Watcher {
46
46
fn new ( ) -> Self {
47
47
let ( sender, receiver) = watch:: channel ( ( ) ) ;
48
- Watcher { sender, receiver }
48
+ Watcher {
49
+ sender : Arc :: new ( sender) ,
50
+ receiver,
51
+ }
49
52
}
50
53
54
+ #[ allow( dead_code) ]
51
55
fn send ( & self ) {
52
56
// Unwrap: `self` holds a receiver.
53
57
self . sender . send ( ( ) ) . unwrap ( )
@@ -147,6 +151,7 @@ impl ChainHeadUpdateListener {
147
151
) {
148
152
// Process chain head updates in a dedicated task
149
153
graph:: spawn ( async move {
154
+ let sending_to_watcher = Arc :: new ( AtomicBool :: new ( false ) ) ;
150
155
while let Some ( notification) = receiver. recv ( ) . await {
151
156
// Create ChainHeadUpdate from JSON
152
157
let update: ChainHeadUpdate =
@@ -173,9 +178,19 @@ impl ChainHeadUpdateListener {
173
178
174
179
// If there are subscriptions for this network, notify them.
175
180
if let Some ( watcher) = watchers. read ( & logger) . get ( & update. network_name ) {
176
- debug ! ( logger, "sending chain head update" ; "network" => & update. network_name) ;
177
- watcher. send ( ) ;
178
- debug ! ( logger, "chain head update sent" ; "network" => & update. network_name) ;
181
+ // Due to a tokio bug, we must assume that the watcher can deadlock, see
182
+ // https://github.com/tokio-rs/tokio/issues/4246.
183
+ if !sending_to_watcher. load ( atomic:: Ordering :: SeqCst ) {
184
+ let sending_to_watcher = sending_to_watcher. cheap_clone ( ) ;
185
+ let sender = watcher. sender . cheap_clone ( ) ;
186
+ tokio:: task:: spawn_blocking ( move || {
187
+ sending_to_watcher. store ( true , atomic:: Ordering :: SeqCst ) ;
188
+ sender. send ( ( ) ) . unwrap ( ) ;
189
+ sending_to_watcher. store ( false , atomic:: Ordering :: SeqCst ) ;
190
+ } ) ;
191
+ } else {
192
+ debug ! ( logger, "skipping chain head update, watcher is deadlocked" ; "network" => & update. network_name) ;
193
+ }
179
194
}
180
195
}
181
196
} ) ;
0 commit comments