I'd like to briefly discuss service discovery as well as a general design that may work. I created a PR #72 that would fix an issue with tye deploy
, however the more I unwrap the issue, the more I think we need to setup a good design across the board, between tye init
, tye run
, and tye deploy
.
Problem statement:
Today, when we setup service discovery between different services, we use environment variables in the shape of:
service:{name}:port
service:{name}:protocol
service:{name}:host
where name is the name of the service you would like to call. A URI can easily be created from this infromation, as seen here: https://github.com/dotnet/tye/blob/master/samples/multi-project/frontend/ConfigurationExtensions.cs#L9.
This all works fine and dandy when each service only has one binding, however this falls apart when multiple bindings are introduced.
For a single binding, our tye.yaml file would look like the following:
name: single-project
services:
- name: test-project
project: test-project\test-project.csproj
bindings:
- port: 80
When getting each of the following values:
service:test-project:port = 80
service:test-project:protocol = (default is http)
service:test-project:host = (default is localhost for tye run, and the service name for tye deploy)
This will work all scenarios currently.
Now let's move to two bindings, tye.yaml could/would look like:
name: single-project
services:
- name: test-project
project: test-project\test-project.csproj
bindings:
- port: 80
- port: 443
Today, this actually works, and will create two bindings for the project. However, there are many issues with this today:
- tye run doesn't set environment variables for service discovery correctly, last one wins
- tye run doesn't know which protocol each port is using. To clarify, the protocol here would be http vs https, which we may want to discuss further in the future.
- tye bindings don't have a name here, so they can't be gotten by the convention of service:test-project:{name}:host
With 3 or more bindings, the problems get a bit more interesting, but let's focus on two for now.
Proposal
The first proposal I'd like to require is that if there are 2+ bindings, that there must be some way to reference them by name such that both are available. For now, I'd propose that we require a name for bindings if there are multiple, for example:
name: single-project
services:
- name: test-project
project: test-project\test-project.csproj
bindings:
- name: http
port: 80
- name: https
port: 443
However, if we have multiple bindings, suddenly doing service:test-project:port wouldn't return a value; you'd need to do service:test-project:http:port to get the http port. This is a problem as suddenly adding an https binding causes your service discovery to break.
The next proposal is to automatically fill service:test-project:port with the http port as well as equivalent variables. Right now, my proposal is to hard code looking for the name "http" when supplying values for these variables.
How this looks E2E
tye init: Instead of just putting the port in for the bindings section based on looking at the launchsettings.json, supply default names of http and https based on the protocol.
tye run: Write service:{name}:{bindingname}:port for service discovery. If name "http" is specified, write that to service:{name}:port. If no tye.yaml file is present, do the same convention in tye init.
tye deploy: From what I can tell, the same as tye run.
Open questions
- Do we really need names if we could just use protocol instead? What would that look like?
- Should we use the name "http" as the default? What about just taking the first one?
- If there is only one port (http), you can't reference service:{name}:http:port. Is that a big deal here?