@@ -19,6 +19,7 @@ import 'package:meta/meta.dart';
19
19
// ignore: implementation_imports
20
20
import 'package:pana/src/dartdoc/pub_dartdoc_data.dart' ;
21
21
import 'package:pool/pool.dart' ;
22
+ import 'package:pub_dev/shared/monitoring.dart' ;
22
23
import 'package:retry/retry.dart' ;
23
24
24
25
import '../../publisher/backend.dart' ;
@@ -55,6 +56,10 @@ final Logger _logger = Logger('pub.search.backend');
55
56
/// building or updating the snapshot.
56
57
const _defaultSnapshotBuildConcurrency = 8 ;
57
58
59
+ /// The (approximate) amount of time while the process holds the lock
60
+ /// and works on index building and updates.
61
+ const _maxLockHoldPeriod = Duration (days: 1 );
62
+
58
63
/// Sets the backend service.
59
64
void registerSearchBackend (SearchBackend backend) =>
60
65
ss.register (#_searchBackend, backend);
@@ -101,15 +106,28 @@ class SearchBackend {
101
106
'$runtimeVersion /search/update-snapshot' ,
102
107
expiration: Duration (minutes: 20 ),
103
108
);
109
+ final started = clock.now ();
104
110
while (true ) {
105
111
try {
106
112
await lock.withClaim ((claim) async {
107
- await doCreateAndUpdateSnapshot (claim);
113
+ // Force timeout exception if the process does not release the lock.
114
+ final lockHoldTimeout = _maxLockHoldPeriod + Duration (hours: 1 );
115
+ await doCreateAndUpdateSnapshot (claim).timeout (lockHoldTimeout);
108
116
});
109
117
} catch (e, st) {
110
- _logger.warning ('Snapshot update failed.' , e, st);
118
+ _logger.pubNoticeShout (
119
+ 'snapshot-building' , 'Snapshot update failed.' , e, st);
120
+ // Force waiting at least an hour before we rethrow the exception
121
+ final elapsed = clock.now ().difference (started);
122
+ if (elapsed < Duration (hours: 1 )) {
123
+ _logger.warning ('Waiting before rethrowing exception.' , e, st);
124
+ await Future .delayed (Duration (hours: 1 ) - elapsed);
125
+ }
126
+ // Throwing here will crash the VM and force the instance to restart.
127
+ rethrow ;
111
128
}
112
- // Wait for 1 minutes for sanity, before trying again.
129
+
130
+ // Allow another instance to get the lock and build the index.
113
131
await Future .delayed (Duration (minutes: 1 ));
114
132
}
115
133
}
@@ -124,7 +142,7 @@ class SearchBackend {
124
142
125
143
// The claim will be released after a day, another process may
126
144
// start to build the snapshot from scratch again.
127
- final workUntil = clock.now ().add (Duration (days : 1 ) );
145
+ final workUntil = clock.now ().add (_maxLockHoldPeriod );
128
146
129
147
// creating snapshot from scratch
130
148
final snapshot = SearchSnapshot ();
0 commit comments