Ejemplo n.º 1
0
        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);
        }
Ejemplo n.º 2
0
        private async Task <ActiveContainer> CreateAndStartContainerAsync(CancellationToken cancellationToken)
        {
            var containerName = _containerNameFormat.GeneratePreallocatedName();

            _logger.LogDebug($"Allocating container {containerName}");
            var containerId = (await _dockerClient.Containers.CreateContainerAsync(new CreateContainerParameters {
                Name = containerName,
                Image = "mcr.microsoft.com/dotnet/runtime:5.0",
                Cmd = new[] { @"c:\\app\SharpLab.Container.exe" },

                AttachStdout = true,
                AttachStdin = true,
                OpenStdin = true,
                StdinOnce = true,

                NetworkDisabled = true,
                HostConfig = new HostConfig {
                    Isolation = "process",
                    Mounts = new[] {
                        new Mount {
                            Source = AppDomain.CurrentDomain.BaseDirectory,
                            Target = @"c:\app",
                            Type = "bind",
                            ReadOnly = true
                        }
                    },
                    Memory = 100 * 1024 * 1024,
                    CPUQuota = 50000,

                    AutoRemove = true
                }
            }, cancellationToken)).ID;

            MultiplexedStream?stream = null;
            ActiveContainer   container;

            try {
                stream = await _dockerClient.Containers.AttachContainerAsync(containerId, tty : false, new ContainerAttachParameters {
                    Stream = true,
                    Stdin  = true,
                    Stdout = true
                }, cancellationToken);

                await _dockerClient.Containers.StartContainerAsync(containerId, new ContainerStartParameters(), cancellationToken);

                container = new ActiveContainer(containerId, stream);

                var outputBuffer = ArrayPool <byte> .Shared.Rent(2048);

                try {
                    var result = await _warmupExecutionProcessor.ExecuteInContainerAsync(
                        container, _warmupAssemblyBytes, outputBuffer, includePerformance : false, cancellationToken
                        );

                    if (!result.IsOutputReadSuccess)
                    {
                        throw new Exception($"Warmup output failed for container {containerName}:\r\n" + Encoding.UTF8.GetString(result.Output.Span) + Encoding.UTF8.GetString(result.OutputReadFailureMessage.Span));
                    }
                }
                finally {
                    ArrayPool <byte> .Shared.Return(outputBuffer);
                }

                _logger.LogDebug($"Allocated container {containerName}");
            }
            catch {
                _containerCleanup.QueueForCleanup(containerId, stream);
                throw;
            }

            return(container);
        }