コード例 #1
0
        /// <summary>
        ///     AcquireAsync the lock, waiting as long as it takes or until the configured timeout.
        /// </summary>
        public async Task <LockAcquisitionResult> AcquireAsync(Context context, TimeSpan waitTimeout)
        {
            _tracer.Info(context, $"Acquiring lock file=[{_lockFilePath}]");

            _fileSystem.CreateDirectory(_lockFilePath.GetParent());

            DateTime  timeOutTime            = DateTime.UtcNow + waitTimeout;
            Exception?lastException          = null;
            int?      lastCompetingProcessId = null;

            while (DateTime.UtcNow < timeOutTime)
            {
                try
                {
                    // Anything other than FileShare.None is effectively ignored in Unix
                    FileShare fileShare = BuildXL.Utilities.OperatingSystemHelper.IsUnixOS ? FileShare.None : FileShare.Read;

                    _lockFile = await _fileSystem.OpenSafeAsync(
                        _lockFilePath, FileAccess.Write, FileMode.OpenOrCreate, fileShare);

                    using (var writer = new StreamWriter(_lockFile, UTF8WithoutBom, bufferSize: 4096, leaveOpen: true))
                    {
                        await writer.WriteLineAsync(
                            $"Lock acquired at {DateTime.UtcNow:O} by computer [{Environment.MachineName}] running command line [{Environment.CommandLine}] with process id [{Process.GetCurrentProcess().Id}]"
                            );
                    }

                    _tracer.Info(context, $"Acquired lock file=[{_lockFilePath}]");

                    await _lockFile.FlushAsync();

                    return(LockAcquisitionResult.Acquired());
                }
                catch (IOException ioException)
                {
                    lastException = ioException;
                }
                catch (UnauthorizedAccessException accessException)
                {
                    lastException = accessException;
                }

                try
                {
                    string?contents = await _fileSystem.TryReadFileAsync(_lockFilePath);

                    if (contents != null)
                    {
                        _tracer.Diagnostic(context, $"Lock file=[{_lockFilePath}] contains [{contents}]");
                        lastCompetingProcessId = TryExtractProcessIdFromLockFilesContent(contents);
                    }
                }
                catch (Exception readLockFileException)
                {
                    string message = readLockFileException is UnauthorizedAccessException ae ? ae.Message : readLockFileException.ToString();
                    // This is just extra cautious. We shouldn't fail hard being unable to get this diagnostic information.
                    _tracer.Info(
                        context,
                        $"Unable to read contents of lock file=[{_lockFilePath}] because [{message}]");
                }

                await Task.Delay(_pollingInterval);
            }

            string lastProcessIdText = lastCompetingProcessId == null ? string.Empty : " Competing process Id: " + lastCompetingProcessId;

            _tracer.Info(
                context,
                $"Timed out trying to acquire lock file=[{_lockFilePath}].{lastProcessIdText} Last exception was=[{lastException}]");

            return(LockAcquisitionResult.Failed(waitTimeout, lastCompetingProcessId, TryGetProcessName(lastCompetingProcessId), lastException));
        }