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

Hot Reloading: Kubernetes Component hot reloading #7260

Merged
merged 33 commits into from Jan 8, 2024

Conversation

JoshVanL
Copy link
Contributor

Branched from #7239

Part of #1172

Adds hot reloading functionality to Daprd, which is gated behind the HotReload preview feature.

If enabled, Daprd in Kubernetes mode will watch for Component resource
updates from the Operator. If a resource is detected as changed (spec is
different to what is currently loaded), then Dapr will
close/create/update the resource.

Supports Component except HTTP middlware which requires further
changes to the HTTP server handler machinery. A warning is thrown if hot
reloading is enabled and a HTTP middleware is updated.


When running in Kubernetes mode, the operator loader streams updates from
the Operator API. When an event occurs, the event type will trigger the
resource to be created, updated, or deleted. Updated components will be
closed, and then re-initialized.

We consider a resource to have changed generally if anything apart from
its Kubernetes metadata or type meta object meta has changed, and
therefore needs some kind of reloading.


Currently, if a reloading component errors and spec.ignoreErrors=false
then Daprd will gracefully close, like a component loaded at startup
today. It is intended that in future the component will be re-inited on
a backoff queue in future in the case of errors, even if
spec.ignoreErros=true.

HTTP middleware component hot reloading is not supported as it requires
further changes to the HTTP server handler machinery, and I didn't want
to grow this PR further.

To use the HotReloading feature, which is currently only available as an
alpha feature in Selfhosted mode, users need to add the following
Configuration to the target Daprd;

apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
  name: hotreloading
spec:
  features:
  - name: HotReload
    enabled: true

Copy link

codecov bot commented Nov 30, 2023

Codecov Report

Attention: 84 lines in your changes are missing coverage. Please review.

Comparison is base (70e3f69) 64.70% compared to head (b76e6ac) 64.49%.

Files Patch % Lines
pkg/runtime/hotreload/loader/operator/component.go 0.00% 28 Missing ⚠️
pkg/runtime/hotreload/loader/operator/resource.go 71.42% 18 Missing ⚠️
pkg/operator/api/api.go 27.77% 13 Missing ⚠️
pkg/runtime/runtime.go 31.25% 10 Missing and 1 partial ⚠️
pkg/operator/operator.go 0.00% 10 Missing ⚠️
pkg/runtime/hotreload/loader/operator/operator.go 0.00% 4 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #7260      +/-   ##
==========================================
- Coverage   64.70%   64.49%   -0.21%     
==========================================
  Files         233      236       +3     
  Lines       21517    21639     +122     
==========================================
+ Hits        13922    13957      +35     
- Misses       6396     6482      +86     
- Partials     1199     1200       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@JoshVanL JoshVanL force-pushed the hot-reloading-components-operator-tested branch 2 times, most recently from bc1b9e4 to 4aee6ed Compare December 6, 2023 15:56
JoshVanL added a commit to JoshVanL/dapr that referenced this pull request Dec 11, 2023
Part of dapr#1172
Branched from dapr#7260

Adds support for HTTP middleware hot reloading.

PR adds support for HTTP middlewares to be dynamically updated. The HTTP
Middleware returns a middleware.HTTP pipleine built from a config spec.
This pipeline implements a single handler which it itself runs the spec
configured HTTP middleware chain. When a middleware Component is added
or removed, the HTTP middleware store is updated and both the HTTP
server and App HTTP channel's pipeline's chains are updated dynamically.

Like today, if a pipeline spec contains handlers whose names, version,
or type does not match that from the store, then the handler is skipped
for that chain. Pipeline handler order is preserved (i.e. reverse order).

The middleware store has been made generic so can be used in future for
planned gRPC middleware support.

Middleware init has been moved from the runtime channel manager to the
runtime processor init procedure to allow for dynamic loading. The
middleware HTTP manager is passed to the runtime processor to expose the
store, and relevant built pipelines passed to the HTTP app channel and
HTTP server.

Middleware integration tests has been added for daprd to check
functionality, ordering, and hotreloading,

Signed-off-by: joshvanl <me@joshvanl.dev>
JoshVanL added a commit to JoshVanL/dapr that referenced this pull request Dec 11, 2023
Part of dapr#1172
Branched from dapr#7260

Adds support for actor state store hot reloading.

PR updates the actors package so that the actor state store is dynamically
retrieved from the component store every time the state it invoked. The
passed static actor state store name previously used to retrieve the
state store has been removed.

The component store has been updated to track the current actor state
store. It is no longer tracked by the state processor, and instead the
state processor updates the latest in the component store.

Like before, the actor state store _must_ be configured on Dapr startup,
else the actor subsystem runtime will not be enabled, even if an actor
state store is hot reloaded later.

Adds actor hotreloading integration tests for the actor state store.

Signed-off-by: joshvanl <me@joshvanl.dev>
@JoshVanL JoshVanL added this to the v1.13 milestone Dec 11, 2023
Part of dapr#1172

Adds hot reloading functionality to Daprd, which is gated behind the HotReload preview feature.

If enabled, Daprd in Selfhosted mode will watch for resource updates
from watching the resource directory(s). If a resource is detected as
changed (spec is different to what is currently loaded), then Dapr will
close/create/update the resource.

Supports Component _except_ HTTP middlware which requires further
changes to the HTTP server handler machinery. A warning is thrown if hot
reloading is enabled and a HTTP middleware is updated.

The hot reloader reconciler is made generic to enable other resource
types to be added in future.

---

When running in standalone mode, the disk loader watches the directories
passed by --resources-path for updates to yaml files containing
Components.

When an event occurs, the reconciler and differ are responsible for
determining whether any resources have been created, updated, or
deleted, by comparing the local store specs with that of the remote. If
any have changed, the resource is closed (if it exists), and then
re-initialized (if it exists). A resource will only be closed if it has
been deleted, only initialized if it has been created, and closed &
initialized if it has been updated.

We consider a resource to have changed generally if anything apart from
its Kubernetes metadata or type meta object meta has changed, and
therefore needs some kind of reloading.

---

Currently, if a reloading component errors and `spec.ignoreErrors=false`
then Daprd will gracefully close, like a component loaded at startup
today. It is intended that in future the component will be re-inited on
a backoff queue in future in the case of errors, even if
`spec.ignoreErros=true`.

HTTP middleware component hot reloading is not supported as it requires
further changes to the HTTP server handler machinery, and I didn't want
to grow this PR further.

To use the HotReloading feature, which is currently only available as an
alpha feature in Selfhosted mode, users need to add the following
Configuration to the target Daprd;

```yaml
apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
  name: hotreloading
spec:
  features:
  - name: HotReload
    enabled: true
```

Signed-off-by: joshvanl <me@joshvanl.dev>
Signed-off-by: joshvanl <me@joshvanl.dev>
Signed-off-by: joshvanl <me@joshvanl.dev>
Signed-off-by: joshvanl <me@joshvanl.dev>
each event

Signed-off-by: joshvanl <me@joshvanl.dev>
Signed-off-by: joshvanl <me@joshvanl.dev>
Signed-off-by: joshvanl <me@joshvanl.dev>
Signed-off-by: joshvanl <me@joshvanl.dev>
Signed-off-by: joshvanl <me@joshvanl.dev>
Signed-off-by: joshvanl <me@joshvanl.dev>
Part of dapr#1172

Adds hot reloading functionality to Daprd, which is gated behind the HotReload preview feature.

If enabled, Daprd in Selfhosted mode will watch for resource updates
from watching the resource directory(s). If a resource is detected as
changed (spec is different to what is currently loaded), then Dapr will
close/create/update the resource.

Supports Component _except_ HTTP middlware which requires further
changes to the HTTP server handler machinery. A warning is thrown if hot
reloading is enabled and a HTTP middleware is updated.

The hot reloader reconciler is made generic to enable other resource
types to be added in future.

---

When running in standalone mode, the disk loader watches the directories
passed by --resources-path for updates to yaml files containing
Components.

When an event occurs, the reconciler and differ are responsible for
determining whether any resources have been created, updated, or
deleted, by comparing the local store specs with that of the remote. If
any have changed, the resource is closed (if it exists), and then
re-initialized (if it exists). A resource will only be closed if it has
been deleted, only initialized if it has been created, and closed &
initialized if it has been updated.

We consider a resource to have changed generally if anything apart from
its Kubernetes metadata or type meta object meta has changed, and
therefore needs some kind of reloading.

---

Currently, if a reloading component errors and `spec.ignoreErrors=false`
then Daprd will gracefully close, like a component loaded at startup
today. It is intended that in future the component will be re-inited on
a backoff queue in future in the case of errors, even if
`spec.ignoreErros=true`.

HTTP middleware component hot reloading is not supported as it requires
further changes to the HTTP server handler machinery, and I didn't want
to grow this PR further.

To use the HotReloading feature, which is currently only available as an
alpha feature in Selfhosted mode, users need to add the following
Configuration to the target Daprd;

```yaml
apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
  name: hotreloading
spec:
  features:
  - name: HotReload
    enabled: true
```

Signed-off-by: joshvanl <me@joshvanl.dev>
Signed-off-by: joshvanl <me@joshvanl.dev>
Branched from dapr#7239

Part of dapr#1172

Adds hot reloading functionality to Daprd, which is gated behind the HotReload preview feature.

If enabled, Daprd in Kubernetes mode will watch for Component resource
updates from the Operator. If a resource is detected as changed (spec is
different to what is currently loaded), then Dapr will
close/create/update the resource.

Supports Component _except_ HTTP middlware which requires further
changes to the HTTP server handler machinery. A warning is thrown if hot
reloading is enabled and a HTTP middleware is updated.

---

When running in Kubernetes mode, the operator loader streams updates from
the Operator API. When an event occurs, the event type will trigger the
resource to be created, updated, or deleted. Updated components will be
closed, and then re-initialized.

We consider a resource to have changed generally if anything apart from
its Kubernetes metadata or type meta object meta has changed, and
therefore needs some kind of reloading.

---

Currently, if a reloading component errors and `spec.ignoreErrors=false`
then Daprd will gracefully close, like a component loaded at startup
today. It is intended that in future the component will be re-inited on
a backoff queue in future in the case of errors, even if
`spec.ignoreErros=true`.

HTTP middleware component hot reloading is not supported as it requires
further changes to the HTTP server handler machinery, and I didn't want
to grow this PR further.

To use the HotReloading feature, which is currently only available as an
alpha feature in Selfhosted mode, users need to add the following
Configuration to the target Daprd;

```yaml
apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
  name: hotreloading
spec:
  features:
  - name: HotReload
    enabled: true
```

Signed-off-by: joshvanl <me@joshvanl.dev>
Signed-off-by: joshvanl <me@joshvanl.dev>
Signed-off-by: joshvanl <me@joshvanl.dev>
Signed-off-by: joshvanl <me@joshvanl.dev>
Signed-off-by: joshvanl <me@joshvanl.dev>
Signed-off-by: joshvanl <me@joshvanl.dev>
Signed-off-by: joshvanl <me@joshvanl.dev>
Signed-off-by: joshvanl <me@joshvanl.dev>
Part of dapr#1172

Adds hot reloading functionality to Daprd, which is gated behind the HotReload preview feature.

If enabled, Daprd in Selfhosted mode will watch for resource updates
from watching the resource directory(s). If a resource is detected as
changed (spec is different to what is currently loaded), then Dapr will
close/create/update the resource.

Supports Component _except_ HTTP middlware which requires further
changes to the HTTP server handler machinery. A warning is thrown if hot
reloading is enabled and a HTTP middleware is updated.

The hot reloader reconciler is made generic to enable other resource
types to be added in future.

---

When running in standalone mode, the disk loader watches the directories
passed by --resources-path for updates to yaml files containing
Components.

When an event occurs, the reconciler and differ are responsible for
determining whether any resources have been created, updated, or
deleted, by comparing the local store specs with that of the remote. If
any have changed, the resource is closed (if it exists), and then
re-initialized (if it exists). A resource will only be closed if it has
been deleted, only initialized if it has been created, and closed &
initialized if it has been updated.

We consider a resource to have changed generally if anything apart from
its Kubernetes metadata or type meta object meta has changed, and
therefore needs some kind of reloading.

---

Currently, if a reloading component errors and `spec.ignoreErrors=false`
then Daprd will gracefully close, like a component loaded at startup
today. It is intended that in future the component will be re-inited on
a backoff queue in future in the case of errors, even if
`spec.ignoreErros=true`.

HTTP middleware component hot reloading is not supported as it requires
further changes to the HTTP server handler machinery, and I didn't want
to grow this PR further.

To use the HotReloading feature, which is currently only available as an
alpha feature in Selfhosted mode, users need to add the following
Configuration to the target Daprd;

```yaml
apiVersion: dapr.io/v1alpha1
kind: Configuration
metadata:
  name: hotreloading
spec:
  features:
  - name: HotReload
    enabled: true
```

Signed-off-by: joshvanl <me@joshvanl.dev>
Signed-off-by: joshvanl <me@joshvanl.dev>
Signed-off-by: joshvanl <me@joshvanl.dev>
Signed-off-by: joshvanl <me@joshvanl.dev>
Signed-off-by: joshvanl <me@joshvanl.dev>
Signed-off-by: joshvanl <me@joshvanl.dev>
Signed-off-by: joshvanl <me@joshvanl.dev>
Signed-off-by: joshvanl <me@joshvanl.dev>
@JoshVanL JoshVanL force-pushed the hot-reloading-components-operator-tested branch from 4aee6ed to f3e5d60 Compare December 27, 2023 17:01
@JoshVanL JoshVanL marked this pull request as ready for review December 27, 2023 17:01
@JoshVanL JoshVanL requested review from a team as code owners December 27, 2023 17:01
pkg/apis/configuration/v1alpha1/types.go Outdated Show resolved Hide resolved
pkg/apis/resiliency/v1alpha1/types.go Outdated Show resolved Hide resolved
pkg/config/configuration.go Outdated Show resolved Hide resolved
pkg/runtime/hotreload/loader/operator/operator.go Outdated Show resolved Hide resolved
pkg/runtime/hotreload/loader/operator/resource.go Outdated Show resolved Hide resolved
pkg/runtime/hotreload/loader/operator/resource.go Outdated Show resolved Hide resolved
pkg/runtime/runtime.go Outdated Show resolved Hide resolved
@JoshVanL JoshVanL added the autoupdate DaprBot will keep the Pull Request up to date with master branch label Jan 2, 2024
@JoshVanL
Copy link
Contributor Author

JoshVanL commented Jan 2, 2024

Thanks @ItalyPaleAle, done!

Signed-off-by: joshvanl <me@joshvanl.dev>

func (r *resource[T]) Stream(ctx context.Context) (<-chan *loader.Event[T], error) {
if r.closed.Load() {
return nil, errors.New("stream is closed")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Who is responsible to re-establish the stream if its closed?

Copy link
Contributor Author

@JoshVanL JoshVanL Jan 3, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a sanity check to return early if we call Stream after the resource streamer manager has been closed (i.e. we are shutting down). Here we retry forever with an exponential backoff until the context is cancelled to reconnect to the operator:

https://github.com/dapr/dapr/pull/7260/files#diff-1e05ef0dac6089bfebe37de39be1346f5722fb7c8c88c78f686d8c77150be98eR139-R155

@yaron2 yaron2 merged commit bfcff0a into dapr:master Jan 8, 2024
17 of 22 checks passed
JoshVanL added a commit to JoshVanL/dapr that referenced this pull request Jan 9, 2024
Part of dapr#1172
Branched from dapr#7260

Adds support for HTTP middleware hot reloading.

PR adds support for HTTP middlewares to be dynamically updated. The HTTP
Middleware returns a middleware.HTTP pipleine built from a config spec.
This pipeline implements a single handler which it itself runs the spec
configured HTTP middleware chain. When a middleware Component is added
or removed, the HTTP middleware store is updated and both the HTTP
server and App HTTP channel's pipeline's chains are updated dynamically.

Like today, if a pipeline spec contains handlers whose names, version,
or type does not match that from the store, then the handler is skipped
for that chain. Pipeline handler order is preserved (i.e. reverse order).

The middleware store has been made generic so can be used in future for
planned gRPC middleware support.

Middleware init has been moved from the runtime channel manager to the
runtime processor init procedure to allow for dynamic loading. The
middleware HTTP manager is passed to the runtime processor to expose the
store, and relevant built pipelines passed to the HTTP app channel and
HTTP server.

Middleware integration tests has been added for daprd to check
functionality, ordering, and hotreloading,

Signed-off-by: joshvanl <me@joshvanl.dev>
JoshVanL added a commit to JoshVanL/dapr that referenced this pull request Jan 9, 2024
Part of dapr#1172
Branched from dapr#7260

Adds support for actor state store hot reloading.

PR updates the actors package so that the actor state store is dynamically
retrieved from the component store every time the state it invoked. The
passed static actor state store name previously used to retrieve the
state store has been removed.

The component store has been updated to track the current actor state
store. It is no longer tracked by the state processor, and instead the
state processor updates the latest in the component store.

Like before, the actor state store _must_ be configured on Dapr startup,
else the actor subsystem runtime will not be enabled, even if an actor
state store is hot reloaded later.

Adds actor hotreloading integration tests for the actor state store.

Signed-off-by: joshvanl <me@joshvanl.dev>
JoshVanL added a commit to JoshVanL/dapr that referenced this pull request Jan 14, 2024
Part of dapr#1172
Branched from dapr#7260

Adds support for HTTP middleware hot reloading.

PR adds support for HTTP middlewares to be dynamically updated. The HTTP
Middleware returns a middleware.HTTP pipleine built from a config spec.
This pipeline implements a single handler which it itself runs the spec
configured HTTP middleware chain. When a middleware Component is added
or removed, the HTTP middleware store is updated and both the HTTP
server and App HTTP channel's pipeline's chains are updated dynamically.

Like today, if a pipeline spec contains handlers whose names, version,
or type does not match that from the store, then the handler is skipped
for that chain. Pipeline handler order is preserved (i.e. reverse order).

The middleware store has been made generic so can be used in future for
planned gRPC middleware support.

Middleware init has been moved from the runtime channel manager to the
runtime processor init procedure to allow for dynamic loading. The
middleware HTTP manager is passed to the runtime processor to expose the
store, and relevant built pipelines passed to the HTTP app channel and
HTTP server.

Middleware integration tests has been added for daprd to check
functionality, ordering, and hotreloading,

Signed-off-by: joshvanl <me@joshvanl.dev>
JoshVanL added a commit to JoshVanL/dapr that referenced this pull request Jan 18, 2024
Part of dapr#1172
Branched from dapr#7260

Adds support for HTTP middleware hot reloading.

PR adds support for HTTP middlewares to be dynamically updated. The HTTP
Middleware returns a middleware.HTTP pipleine built from a config spec.
This pipeline implements a single handler which it itself runs the spec
configured HTTP middleware chain. When a middleware Component is added
or removed, the HTTP middleware store is updated and both the HTTP
server and App HTTP channel's pipeline's chains are updated dynamically.

Like today, if a pipeline spec contains handlers whose names, version,
or type does not match that from the store, then the handler is skipped
for that chain. Pipeline handler order is preserved (i.e. reverse order).

The middleware store has been made generic so can be used in future for
planned gRPC middleware support.

Middleware init has been moved from the runtime channel manager to the
runtime processor init procedure to allow for dynamic loading. The
middleware HTTP manager is passed to the runtime processor to expose the
store, and relevant built pipelines passed to the HTTP app channel and
HTTP server.

Middleware integration tests has been added for daprd to check
functionality, ordering, and hotreloading,

Signed-off-by: joshvanl <me@joshvanl.dev>
JoshVanL added a commit to JoshVanL/dapr that referenced this pull request Jan 25, 2024
Part of dapr#1172
Branched from dapr#7260

Adds support for HTTP middleware hot reloading.

PR adds support for HTTP middlewares to be dynamically updated. The HTTP
Middleware returns a middleware.HTTP pipleine built from a config spec.
This pipeline implements a single handler which it itself runs the spec
configured HTTP middleware chain. When a middleware Component is added
or removed, the HTTP middleware store is updated and both the HTTP
server and App HTTP channel's pipeline's chains are updated dynamically.

Like today, if a pipeline spec contains handlers whose names, version,
or type does not match that from the store, then the handler is skipped
for that chain. Pipeline handler order is preserved (i.e. reverse order).

The middleware store has been made generic so can be used in future for
planned gRPC middleware support.

Middleware init has been moved from the runtime channel manager to the
runtime processor init procedure to allow for dynamic loading. The
middleware HTTP manager is passed to the runtime processor to expose the
store, and relevant built pipelines passed to the HTTP app channel and
HTTP server.

Middleware integration tests has been added for daprd to check
functionality, ordering, and hotreloading,

Signed-off-by: joshvanl <me@joshvanl.dev>
artursouza pushed a commit that referenced this pull request Jan 26, 2024
* Hot Reloading: HTTP Middleware Reloading

Part of #1172
Branched from #7260

Adds support for HTTP middleware hot reloading.

PR adds support for HTTP middlewares to be dynamically updated. The HTTP
Middleware returns a middleware.HTTP pipleine built from a config spec.
This pipeline implements a single handler which it itself runs the spec
configured HTTP middleware chain. When a middleware Component is added
or removed, the HTTP middleware store is updated and both the HTTP
server and App HTTP channel's pipeline's chains are updated dynamically.

Like today, if a pipeline spec contains handlers whose names, version,
or type does not match that from the store, then the handler is skipped
for that chain. Pipeline handler order is preserved (i.e. reverse order).

The middleware store has been made generic so can be used in future for
planned gRPC middleware support.

Middleware init has been moved from the runtime channel manager to the
runtime processor init procedure to allow for dynamic loading. The
middleware HTTP manager is passed to the runtime processor to expose the
store, and relevant built pipelines passed to the HTTP app channel and
HTTP server.

Middleware integration tests has been added for daprd to check
functionality, ordering, and hotreloading,

Signed-off-by: joshvanl <me@joshvanl.dev>

* Update pkg/middleware/http/http.go

Co-authored-by: Loong Dai <long0dai@foxmail.com>
Signed-off-by: Josh van Leeuwen <me@joshvanl.dev>

* Remove false comment

Signed-off-by: joshvanl <me@joshvanl.dev>

* Update middleware tests due to new reserved dapr Component name

Signed-off-by: joshvanl <me@joshvanl.dev>

* Fix http channel test panic

Signed-off-by: joshvanl <me@joshvanl.dev>

* Remove workflow.dapr component from middleware integration test
metadata component checks

Signed-off-by: joshvanl <me@joshvanl.dev>

---------

Signed-off-by: joshvanl <me@joshvanl.dev>
Signed-off-by: Josh van Leeuwen <me@joshvanl.dev>
Co-authored-by: Loong Dai <long0dai@foxmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
autoupdate DaprBot will keep the Pull Request up to date with master branch
Projects
Development

Successfully merging this pull request may close these issues.

None yet

4 participants