@@ -28,6 +28,10 @@ internal sealed class FileDataSource : IDataSource
2828 private volatile int _lastVersion ;
2929 private object _updateLock = new object ( ) ;
3030
31+ private const int MaxRetries = 5 ;
32+ private readonly TimeSpan RetryDelay = TimeSpan . FromSeconds ( 0.6 ) ;
33+ private readonly Dictionary < string , int > _retryCounts = new Dictionary < string , int > ( ) ;
34+
3135 public FileDataSource ( IDataSourceUpdates dataSourceUpdates , FileDataTypes . IFileReader fileReader ,
3236 List < string > paths , bool autoUpdate , Func < string , object > alternateParser , bool skipMissingPaths ,
3337 FileDataTypes . DuplicateKeysHandling duplicateKeysHandling ,
@@ -102,17 +106,51 @@ private void LoadAll()
102106 _logger . Debug ( "file data: {0}" , content ) ;
103107 var data = _parser . Parse ( content , version ) ;
104108 _dataMerger . AddToData ( data , flags , segments ) ;
109+ // Remove any retry count associated with this path.
110+ _retryCounts . Remove ( path ) ;
105111 }
106112 catch ( FileNotFoundException ) when ( _skipMissingPaths )
107113 {
108114 _logger . Debug ( "{0}: {1}" , path , "File not found" ) ;
109115 }
116+ catch ( System . Text . Json . JsonException )
117+ {
118+ // We may have received the notification of a file change while the file was being written.
119+ // So we may read an empty or partially written file. So, when we encounter a JSON parsing issue
120+ // we will retry after a short delay.
121+ // We will retry up to MaxRetries times before giving up.
122+ if ( ! _retryCounts . ContainsKey ( path ) )
123+ {
124+ _retryCounts [ path ] = 0 ;
125+ }
126+ _retryCounts [ path ] ++ ;
127+
128+ if ( _retryCounts [ path ] < MaxRetries )
129+ {
130+ _logger . Warn ( "{0}: {1}" , path , "Failed to parse file, retrying in " + RetryDelay . TotalMilliseconds + " milliseconds" ) ;
131+ Task . Run ( async ( ) =>
132+ {
133+ await Task . Delay ( RetryDelay ) ;
134+ LoadAll ( ) ;
135+ } ) ;
136+ }
137+ else
138+ {
139+ _logger . Error ( "{0}: {1}" , path , "Failed to parse file after " + MaxRetries + " retries" ) ;
140+ }
141+
142+ return ;
143+ }
110144 catch ( Exception e )
111145 {
112146 LogHelpers . LogException ( _logger , "Failed to load " + path , e ) ;
113147 return ;
114148 }
115149 }
150+
151+ // If any files failed to load, from anything other than not existing, then that
152+ // update would fail. This behavior is retained with the addition of the retry. But it should be
153+ // examined.
116154
117155 var allData = new FullDataSet < ItemDescriptor > (
118156 ImmutableDictionary . Create < DataKind , KeyedItems < ItemDescriptor > > ( )
0 commit comments