public async Task StartAsync(CancellationToken cancellationToken)
        {
            ThrowIfDisposed();

            if (_watcher != null && _watcher.EnableRaisingEvents)
            {
                throw new InvalidOperationException("The listener has already been started.");
            }

            if (string.IsNullOrEmpty(_config.RootPath) || !Directory.Exists(_config.RootPath))
            {
                throw new InvalidOperationException(string.Format("Path '{0}' is invalid. FilesConfiguration.RootPath must be set to a valid directory location.", _config.RootPath));
            }

            CreateFileWatcher();

            FileProcessorFactoryContext context = new FileProcessorFactoryContext(_config, _attribute, _triggerExecutor, _trace);
            _processor = _config.ProcessorFactory.CreateFileProcessor(context);

            ExecutionDataflowBlockOptions options = new ExecutionDataflowBlockOptions
            {
                BoundedCapacity = _processor.MaxQueueSize,
                MaxDegreeOfParallelism = _processor.MaxDegreeOfParallelism,
            };
            _workQueue = new ActionBlock<FileSystemEventArgs>(async (e) => await ProcessWorkItem(e), options);

            // on startup, process any preexisting files that haven't been processed yet
            ProcessFiles();

            // Create a timer to cleanup processed files.
            // The timer doesn't auto-reset. It will reset itself
            // when we receive more file events
            _cleanupTimer = new System.Timers.Timer()
            {
                AutoReset = false,
                Interval = _rand.Next(5 * 1000, 8 * 1000)
            };
            _cleanupTimer.Elapsed += OnCleanupTimer;
            _cleanupTimer.Start();

            await Task.FromResult<bool>(true);
        }
        public FileProcessorTests()
        {
            rootPath = Path.GetTempPath();
            combinedTestFilePath = Path.Combine(rootPath, attributeSubPath);
            Directory.CreateDirectory(combinedTestFilePath);
            DeleteTestFiles(combinedTestFilePath);

            config = new FilesConfiguration()
            {
                RootPath = rootPath
            };
            
            FileTriggerAttribute attribute = new FileTriggerAttribute(attributeSubPath, "*.dat");
            processor = CreateTestProcessor(attribute);

            JsonSerializerSettings settings = new JsonSerializerSettings
            {
                DateFormatHandling = DateFormatHandling.IsoDateFormat,
            };
            _serializer = JsonSerializer.Create(settings);

            Environment.SetEnvironmentVariable("WEBSITE_INSTANCE_ID", InstanceId);
        }
        public async Task ProcessFileAsync_ChangeTypeCreate_Success()
        {
            FileTriggerAttribute attribute = new FileTriggerAttribute(attributeSubPath, "*.dat");
            processor = CreateTestProcessor(attribute);

            string testFile = WriteTestFile("dat");

            FunctionResult result = new FunctionResult(true);
            mockExecutor.Setup(p => p.TryExecuteAsync(It.IsAny<TriggeredFunctionData>(), It.IsAny<CancellationToken>())).ReturnsAsync(result);

            string testFilePath = Path.GetDirectoryName(testFile);
            string testFileName = Path.GetFileName(testFile);
            FileSystemEventArgs eventArgs = new FileSystemEventArgs(WatcherChangeTypes.Created, testFilePath, testFileName);
            bool fileProcessedSuccessfully = await processor.ProcessFileAsync(eventArgs, CancellationToken.None);

            Assert.True(fileProcessedSuccessfully);
            string expectedStatusFile = processor.GetStatusFile(testFile);
            Assert.True(File.Exists(testFile));
            Assert.True(File.Exists(expectedStatusFile));
            string[] lines = File.ReadAllLines(expectedStatusFile);
            Assert.Equal(2, lines.Length);

            StatusFileEntry entry = (StatusFileEntry)_serializer.Deserialize(new StringReader(lines[0]), typeof(StatusFileEntry));
            Assert.Equal(ProcessingState.Processing, entry.State);
            Assert.Equal(WatcherChangeTypes.Created, entry.ChangeType);
            Assert.Equal(InstanceId.Substring(0, 20), entry.InstanceId);

            entry = (StatusFileEntry)_serializer.Deserialize(new StringReader(lines[1]), typeof(StatusFileEntry));
            Assert.Equal(ProcessingState.Processed, entry.State);
            Assert.Equal(WatcherChangeTypes.Created, entry.ChangeType);
            Assert.Equal(InstanceId.Substring(0, 20), entry.InstanceId);
        }