public async Task <ExecutionOutputResult> ExecuteAsync( string sessionId, byte[] assemblyBytes, byte[] outputBufferBytes, bool includePerformance, CancellationToken cancellationToken ) { // Note that _containers are never accessed through multiple threads for the same session id, // so atomicity is not required within same session id using var allocationCancellation = CancellationFactory.ContainerAllocation(cancellationToken); if (_containerPool.GetSessionContainer(sessionId) is not { } container) { if (_crashSuspensionManager.GetSuspension(sessionId, outputBufferBytes) is {} suspension) { return(suspension); } try { container = await _containerPool.AllocateSessionContainerAsync(sessionId, _cleanupWorker.QueueForCleanup, allocationCancellation.Token); } catch (OperationCanceledException ex) { throw new ContainerAllocationException("Failed to allocate container within 5 seconds.", _containerPool.LastContainerPreallocationException ?? ex); } await _dockerClient.Containers.RenameContainerAsync(container.ContainerId, new ContainerRenameParameters { NewName = _containerNameFormat.GenerateSessionContainerName(sessionId) }, cancellationToken); } var result = await _executionProcessor.ExecuteInContainerAsync( container, assemblyBytes, outputBufferBytes, includePerformance, cancellationToken ); if (!result.IsOutputReadSuccess) { var containerCrashed = false; try { var response = await _dockerClient.Containers.InspectContainerAsync(container.ContainerId, cancellationToken); containerCrashed = !response.State.Running; } catch (DockerContainerNotFoundException) { containerCrashed = true; } if (containerCrashed) { _containerPool.RemoveSessionContainer(sessionId); } return(_crashSuspensionManager.SetSuspension(sessionId, result)); } return(result); }
public async Task <ExecutionOutputResult> ExecuteInContainerAsync( ActiveContainer container, byte[] assemblyBytes, byte[] outputBufferBytes, bool includePerformance, CancellationToken cancellationToken ) { var outputStartMarker = Guid.NewGuid(); var outputEndMarker = Guid.NewGuid(); await _stdinWriter.WriteCommandAsync(container.Stream, new ExecuteCommand( assemblyBytes, outputStartMarker, outputEndMarker, includePerformance ), cancellationToken); const int OutputMarkerLength = 36; // length of guid byte[]? outputStartMarkerBytes = null; byte[]? outputEndMarkerBytes = null; try { outputStartMarkerBytes = ArrayPool <byte> .Shared.Rent(OutputMarkerLength); outputEndMarkerBytes = ArrayPool <byte> .Shared.Rent(OutputMarkerLength); Utf8Formatter.TryFormat(outputStartMarker, outputStartMarkerBytes, out _); Utf8Formatter.TryFormat(outputEndMarker, outputEndMarkerBytes, out _); using var executionCancellation = CancellationFactory.ContainerExecution(cancellationToken); return(await _stdoutReader.ReadOutputAsync( container.Stream, outputBufferBytes, outputStartMarkerBytes.AsMemory(0, OutputMarkerLength), outputEndMarkerBytes.AsMemory(0, OutputMarkerLength), executionCancellation.Token )); } finally { if (outputStartMarkerBytes != null) { ArrayPool <byte> .Shared.Return(outputStartMarkerBytes); } if (outputEndMarkerBytes != null) { ArrayPool <byte> .Shared.Return(outputEndMarkerBytes); } } }