-
Notifications
You must be signed in to change notification settings - Fork 239
Support environment configuration #1849
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
Conversation
// ClientConfigCodec is codec configuration for a client. | ||
// | ||
// WARNING: Environment configuration is currently experimental. | ||
type ClientConfigCodec struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe call this ClientConfigRemoteCodec? What, if anything, could ever be configured here for local codec? And, even then, maybe it'd make sense to have them be different sub-configs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It is the codec
field in config and TEMPORAL_CODEC_
prefixed env vars and Codec
field name in the structure in addition to this type name. So I want it to match those. If we want though, I could change the config field name, env var prefix, struct field name, and this type name.
// See [ClientConfig.FromTOML] for details on format. | ||
// | ||
// WARNING: Environment configuration is currently experimental. | ||
func LoadClientConfig(options LoadClientConfigOptions) (ClientConfig, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This and LoadClientOptions
don't have distinct enough names, IMO.
Maybe LoadClientOptionsFromFile
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it's distinct enough given its return type and such, but I can change and change the param structure to LoadClientConfigFromFileOptions
. Would like to wait on other opinions if anyone has any. I am concerned there may also be too-similar naming concerns in other SDKs.
if env == nil { | ||
env = EnvLookupOS | ||
} | ||
if s, ok := env.LookupEnv("TEMPORAL_ADDRESS"); ok { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it probably makes sense to make these all public constants. It helps with both documentation and, since people can technically implement their own lookup, they might want to programmatically use them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't expect this to be where such things are documented. I am expecting docs.temporal.io to house the documentation with these environment variables. I don't expect anyone to ever reference such a constant programmatically either like one might expect with an exported constant.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not? They could be doing it as part of some infra-as-code stuff.
Even more obviously, our own CLI PR could use them!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because the constants are part of the spec that will be documented generally and I am not sure it has enough value making them part of the public API in every SDK (nor do I think that we need to with the other environment variable names such as TEMPORAL_DEBUG
). Clear environment variable names from spec I don't think need to also be exposed user-facing constants unlike other string literals which might.
contrib/envconfig/client_config.go
Outdated
} | ||
|
||
// ToClientOptionsOptions are options for [ClientConfig.ToClientOptions] and [ClientConfigProfile.ToClientOptions]. | ||
type ToClientOptionsOptions struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OptionsOptions
feels a little awkward for a name, but can't think of a great alternative..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Agreed, I had brought this up internally but no good solution was provided. I don't expect users to use this part of the API much.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@cretz I updated my local copy of your Go SDK to commit #362043e and then tried this again.
Following the approach previously described, I tested this with mTLS and found that it now works as expected.
I then attempted to do the same with API Key authentication. I unset the previous four environment variables and then set the following:
TEMPORAL_API_KEY=<redacted>
TEMPORAL_NAMESPACE=tom-dev.a2dd6
TEMPORAL_ADDRESS=us-east-1.aws.api.temporal.io:7233
When I started the Worker, it failed:
$ go run worker/main.go
2025/02/25 13:53:31 INFO No logger configured for temporal client. Created default one.
2025/02/25 13:53:32 Unable to create Temporal client. failed reaching server: rpc error: code = Unauthenticated desc = Jwt is expired
exit status 1
I then looked at the code and realized that perhaps I needed to run this:
$ export TEMPORAL_TLS=true
I then repeated the previous command and found that the Worker now started. I did the same in the other terminal before running the command to start the Workflow, which then completed successfully.
In the end, it seems to work fine, although I think we'd be wise to emphasize in the docs that you must set TEMPORAL_TLS=true
when using API Key authentication with Temporal Cloud, because I think people might overlook it otherwise.
@tomwheeler - that is the error you got originally, I am not sure how EDIT: @tomwheeler - I cannot replicate. With the set TEMPORAL_ADDRESS=us-west-2.aws.api.temporal.io:7233
set TEMPORAL_NAMESPACE=sdk-ci.a2dd6
set TEMPORAL_API_KEY=omitted
go run ./helloworld/worker and in another terminal set TEMPORAL_ADDRESS=us-west-2.aws.api.temporal.io:7233
set TEMPORAL_NAMESPACE=sdk-ci.a2dd6
set TEMPORAL_API_KEY=omitted
go run ./helloworld/starter It works as expected. |
contrib/envconfig/client_config.go
Outdated
// | ||
// WARNING: Environment configuration is currently experimental. | ||
type ClientConfigProfile struct { | ||
Address string |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Don't we generally want all public structs documented?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, though I am not sure it necessarily applies to all public struct fields. I can document it, though I will likely just say it applies to certain client option fields and not give all the details.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Documented struct fields
contrib/envconfig/client_config.go
Outdated
// | ||
// WARNING: Environment configuration is currently experimental. | ||
type ClientConfigTLS struct { | ||
Disabled bool |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So the default will be TLS enabled?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Or are we treating nil
different then the zero value?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
So the default will be TLS enabled?
No, the default is "depends on other fields". If you give an API key the default is enabled, but if you don't the default is disabled (but you can make enabled with any TLS value including TLS itself being set). So this is effectively for those rare cases that have an API key but want to explicitly disable TLS (e.g. self-hosted using JWTs). This is what allows us to just accept an API key env var for cloud and assume TLS.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was jsut confused here because the default of the bool will be false, so that could imply the default of TLS is enable
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unset/false here is "not disabled", not necessarily "enabled". I agree it can be confusing, but I think any alternative is more confusing. Open to other suggestions. We don't want to differentiate between false and unset though as they are the same thing.
} | ||
|
||
// LoadClientOptionsOptions are options for [LoadClientOptions]. | ||
type LoadClientOptionsOptions struct { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I thought we said we didn't want to stutter on Options
here, generally the SDK has used request
instead of option when it hits this
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't think we had settled on this. I thought request was for actual API requests (i.e. RPC calls). But I can change ToClientOptionsOptions
to ToClientOptionsRequest
if you think that's better. It's a bit confusing that some are requests and some are options when they are really all options.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Bump here. Do you think that it's worth suffixing with Request
even though these aren't really requests like you'd have on a client?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am fine with it being Request
even though it is not a client call. OK leaving it as Option
as well since we are consistent in this module at least
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed to OptionsRequest
What was changed
go.temporal.io/sdk/contrib/envconfig
module that supports loadingSee temporalio/features#441, this is mostly based on that proposal with some slight changes.
This SDK may support a few more shortcuts than other SDKs due to its use in CLI. Documentation about file format and which env vars do what will be made available on docs.temporal.io before this launches GA.
Checklist