Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce a new Server API #15006

Closed
davidfowl opened this issue Oct 15, 2019 · 7 comments
Closed

Introduce a new Server API #15006

davidfowl opened this issue Oct 15, 2019 · 7 comments
Assignees
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions 🥌 Bedrock

Comments

@davidfowl
Copy link
Member

davidfowl commented Oct 15, 2019

Servers typically need to do a set of common tasks:

  • They need to implement an accept loop per endpoint
  • They need to track connections
  • They need to implement graceful shutdown
  • They need an efficient way to implement timeouts (which integrates with connection tracking)

The goal of the server API is to:

  • Expose a common way for server bindings
  • This includes exposing a common way for wiring up transports
  • Implement the mechanics described above in a reliable manner
  • Provide an embeddable server API without a dependency on the HTTP stack
public class ServerBuilder
{
    public ServerBuilder(IServiceProvider serviceProvider);

    public IList<ServerBinding> Bindings { get; }

    public TimeSpan HeartBeatInterval { get; set; }

    public IServiceProvider ApplicationServices { get; }

    public Server Build();
}

public class ServerBinding
{
    public ServerBinding(EndPoint endPoint, IConnectionListenerFactory connectionListenerFactory, ConnectionDelegate application);

    public EndPoint EndPoint { get; }
    
    public IConnectionListenerFactory ConnectionListenerFactory { get; }
    
    public ConnectionDelegate Application { get; }
}

public class Server
{
    public Task StartAsync(CancellationToken cancellationToken = default);
    public Task StopAsync(CancellationToken cancellationToken = default);
}

Usage looks like this:

namespace ServerApplication
{
    public class Program
    {
        public static async Task Main(string[] args)
        {
            // Make a servier provider with a logger
            var serviceProvider = new ServiceCollection().AddLogging(builder =>
            {
                builder.AddConsole();
            })
            .BuildServiceProvider();

            var serverBuilder = new ServerBuilder(serviceProvider);
            // Create an instance of the sockets transport
            var socketConnectionListenerFactory = new SocketsConnectionListenerFactory();
            var endpoint = new IPEndPoint(IPAddress.LoopBack, 5050);
            // Simple echo server
            ConnectionDelegate application = connection => connection.Transport.Input.CopyToAsync(connection.Transport.Output);
            // Add the binding to the server
            serverBuilder.Bindings.Add(new ServerBinding(endpoint, socketConnectionListenerFactory, application));
            var server = serverBuilder.Build();
            await server.StartAsync();

            // Wait until a key is pressed
            Console.ReadLine();

            await server.StopAsync();
        }
    }
}

With some syntax sugar, I expect it to look like this:

namespace ServerApplication
{
    public class Program
    {
        public static async Task Main(string[] args)
        {
            // Make a servier provider with a logger
            var serviceProvider = new ServiceCollection().AddLogging(builder =>
            {
                builder.AddConsole();
            })
            .BuildServiceProvider();

            var server = new ServerBuilder(serviceProvider)
                        .UseSockets(sockets =>
                        {
                            sockets.Options.IOQueueCount = Environment.ProcessorCount;

                            sockets.Listen(IPAddress.Loopback, 5010, builder => builder.UseConnectionHandler<EchoServerApplication>());
                        })
                        .Build();

            await server.StartAsync();

            // Wait until a key is pressed
            Console.ReadLine();

            await server.StopAsync();
        }
    }
}
@davidfowl davidfowl added 🥌 Bedrock api-suggestion Early API idea and discussion, it is NOT ready for implementation labels Oct 15, 2019
@davidfowl davidfowl self-assigned this Oct 15, 2019
@davidfowl
Copy link
Member Author

Some things that have come up when trying to implement this API in Kestrel itself:

  • Localhost and Any (*) bindings have special behavior that can't be represented as data. This means the server needs hard coded logic to handle this or we punt on the existing behavior and say it's too special.
  • When testing, it's important for the caller to be able to trigger heartbeats on demand without waiting for a timer to fire. Exposing a HeartBeatInterval is insufficient.

@gfoidl

This comment has been minimized.

@analogrelay analogrelay modified the milestones: 5.0.0-preview1, Backlog Oct 15, 2019
@halter73
Copy link
Member

public TimeSpan ShutdownTimeout { get; set; }

This won't work with the current way WebHost interacts with IServer, since WebHost controls the shutdown timeout by tripping the CancellationToken passed to IServer.StopAsync(token) instead of passing in a TimeSpan.

@davidfowl
Copy link
Member Author

@gfoidl fixed.

@davidfowl
Copy link
Member Author

davidfowl commented Oct 15, 2019

@halter73 good point, the token passed into StopAsync would suffice then. Removed it

@jkotalik
Copy link
Contributor

@davidfowl do you think these kinds of bedrock issues should be transferred to https://github.com/davidfowl/BedrockFramework?

@davidfowl
Copy link
Member Author

Yes we can close this.

@ghost ghost locked as resolved and limited conversation to collaborators Feb 24, 2020
@amcasey amcasey added area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions and removed area-runtime labels Jun 2, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api-suggestion Early API idea and discussion, it is NOT ready for implementation area-networking Includes servers, yarp, json patch, bedrock, websockets, http client factory, and http abstractions 🥌 Bedrock
Projects
None yet
Development

No branches or pull requests

6 participants