Skip to content

Commit

Permalink
helper/schema: Introduce context-aware resource CRUD functions withou…
Browse files Browse the repository at this point in the history
…t default timeout

Reference: #675

The Terraform Plugin SDK has always supported customizable timeouts, declared at the `helper/schema.Resource.Timeouts` level with the operation aware [`helper/schema.ResourceTimeout` type](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema#ResourceTimeout). These were designed to allow practitioners to implement a timeout per resource, e.g.

```terraform
resource "example_thing" "example" {
  timeouts {
    create = "60m"
  }
}
```

Where the resource logic could fetch the timeout value via [`(helper/schema.ResourceData).Timeout()` function](https://pkg.go.dev/github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema#ResourceData.Timeout).

Recently, context-aware resource operation functions were introduced and the existing non-context-aware functions were deprecated. These new context-aware resource operations forcibly introduce an operation timeout (defaults to 20 minutes) for the called logic, e.g.

https://github.com/hashicorp/terraform-plugin-sdk/blob/e21a5bbb73209dcb31f4c9dff3a8c0cec1ca65ac/helper/schema/resource.go#L283-L285

Previously, the non-context-aware resources could be implemented with `helper/schema.Resource.Timeouts.Create` defined and operation logic such as:

```go
func resourceExampleThingCreate(d *schema.ResourceData, meta interface{}) error {
  mutexkv.Lock("somekey")
  defer mutexkv.Unlock("somekey")
  // ... reference to d.Timeout(schema.TimeoutCreate) ...
}
```

Where in this case, the create timeout could be referenced in the code via `d.Timeout(schema.TimeoutCreate)` after the synchronization coordination. The creation timeout only affected this single operation, even if multiple operations were going to occur.

In the case of the context-aware functionality however, the timeout is configured before the mutex. So when multiple operations are waiting on the mutex, they are now sharing the same resource operation timeout. Since the timeout cannot be extended within the resource logic, developers are stuck either setting an arbitrarily high timeout (losing its usefulness) or practitioners are arbitrarily hitting the timeout as they scale out their configuration.

To characterize how some remote systems can require that operations must be serialized or otherwise synchronized:

* Only 1 resource type can be created at a time
* Only 1 child resource type can be created at a time per parent resource
* Only 10 concurrent updates of a resource type can be performed at a time
* Remote system may support configurable synchronization limits (either by the customer or remote system operators)

This essentially means the semantics of the synchronization can be based off resource configuration, operation type, and potentially accordant to the limits set by a remote system.

### Attempted Solutions

```go
&schema.Resource{
	Timeouts: &schema.ResourceTimeout{
		Create: schema.DefaultTimeout(3 * time.Hour),
	},
}
```

This introduces separate CRUD methods that are invoked before the context is set with the timeout, so as to not "force" the resource timeout. If timeout behavior is still desired, developers must manually implement timeout handling in the function logic when using these.

Most developers should prefer the existing context-aware functions and this is documented as such. However, another minor side benefit of these functions is that it also allows developers to upgrade CRUD function signatures for context awareness without logically changing resource behavior, then slowly switch to the timeout functions over time.
  • Loading branch information
bflad authored and paddycarver committed Mar 18, 2021
1 parent fdeafb3 commit 0e34772
Show file tree
Hide file tree
Showing 3 changed files with 713 additions and 309 deletions.
Loading

0 comments on commit 0e34772

Please sign in to comment.