Skip to content

Commit

Permalink
Merge pull request #182 from ably/laura/server-side-batching
Browse files Browse the repository at this point in the history
[INF-4937] Add server-side batching
  • Loading branch information
surminus authored Aug 14, 2024
2 parents 0e0c030 + 1a58b3c commit 9ca554f
Show file tree
Hide file tree
Showing 10 changed files with 176 additions and 6 deletions.
4 changes: 4 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,10 @@
6. Push the branch (`git push origin my-new-feature`)
7. Create a new Pull Request

## Testing

See [DEVELOPING_LOCALLY.md](DEVELOPING_LOCALLY.md) for guidance on performing acceptance tests.

## Release Process

1. Merge all pull requests containing changes intended for this release to `main` branch
Expand Down
2 changes: 1 addition & 1 deletion DEVELOPING_LOCALLY.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ provider_installation {
}
```

Build your changes from the repository root with
Build your changes from the repository root with
```
$ go install
$ cd examples/playground && terraform plan
Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ provider "ably" {
}
```

4. (Optional) Alternatively you can also specify Control API token in the provider configuration directly:
4. (Optional) Alternatively you can also specify Control API token in the provider configuration directly:

```terraform
provider "ably" {
Expand All @@ -50,7 +50,7 @@ provider "ably" {

## Using Ably Terraform provider

This readme gives a basic example; for more examples see the [examples/](examples/) folder, rendered documentation on the Terraform Registry, or [docs folder](docs/) in this repository.
This readme gives a basic example; for more examples see the [examples/](examples/) folder, rendered documentation on the Terraform Registry, or [docs folder](docs/) in this repository.


```terraform
Expand Down Expand Up @@ -84,7 +84,7 @@ resource "ably_queue" "example_queue" {

## Dependencies

This provider uses [Ably Control API](https://ably.com/docs/api/control-api) and [Ably Control Go SDK](https://github.com/ably/ably-control-go) under the hood.
This provider uses [Ably Control API](https://ably.com/docs/api/control-api) and [Ably Control Go SDK](https://github.com/ably/ably-control-go) under the hood.


## Support, feedback and troubleshooting
Expand Down
17 changes: 17 additions & 0 deletions docs/resources/namespace.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,20 @@ resource "ably_namespace" "namespace0" {
tls_only = false
expose_timeserial = false
}
resource "ably_namespace" "namespace_batching" {
app_id = ably_app.app0.id
id = "namespace"
authenticated = false
persisted = false
persist_last = false
push_enabled = false
tls_only = false
expose_timeserial = false
batching_enabled = true
batching_policy = "some-policy"
batching_interval = 100
}
```

<!-- schema generated by tfplugindocs -->
Expand All @@ -36,6 +50,9 @@ resource "ably_namespace" "namespace0" {
### Optional

- `authenticated` (Boolean) Require clients to be authenticated to use channels in this namespace.
- `batching_enabled` (Boolean) If true, channels within this namespace will start batching inbound messages instead of sending them out immediately to subscribers as per the configured policy.
- `batching_interval` (Number) When configured, sets the maximium batching interval in the channel.
- `batching_policy` (String) When configured, sets the policy for message batching.
- `expose_timeserial` (Boolean) If true, messages received on a channel will contain a unique timeserial that can be referenced by later messages for use with message interactions.
- `persist_last` (Boolean) If true, the last message on each channel will persist for 365 days.
- `persisted` (Boolean) If true, messages will be stored for 24 hours.
Expand Down
14 changes: 14 additions & 0 deletions examples/resources/namespace.tf
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,17 @@ resource "ably_namespace" "namespace0" {
tls_only = false
expose_timeserial = false
}

resource "ably_namespace" "namespace_batching" {
app_id = ably_app.app0.id
id = "namespace"
authenticated = false
persisted = false
persist_last = false
push_enabled = false
tls_only = false
expose_timeserial = false
batching_enabled = true
batching_policy = "some-policy"
batching_interval = 100
}
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ module github.com/ably/terraform-provider-ably
go 1.19

require (
github.com/ably/ably-control-go v0.3.0
github.com/ably/ably-control-go v0.4.0
github.com/hashicorp/terraform-plugin-docs v0.13.0
github.com/hashicorp/terraform-plugin-framework v0.16.0
github.com/hashicorp/terraform-plugin-sdk/v2 v2.21.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 h1:YoJbenK9C6
github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
github.com/ably/ably-control-go v0.3.0 h1:m5Y2SHE69Mwg8iDASZxqmlHFSwpejN4s2TgZi3EIVMQ=
github.com/ably/ably-control-go v0.3.0/go.mod h1:TP7gWAy+ga++gX6OZ0DtjwH8oVKKdiaIGQvZvxDKNdk=
github.com/ably/ably-control-go v0.4.0 h1:JouYcHKT2TvvAGPpEPQJcFo5p9k1KfLUr/k9bfy+tYI=
github.com/ably/ably-control-go v0.4.0/go.mod h1:TP7gWAy+ga++gX6OZ0DtjwH8oVKKdiaIGQvZvxDKNdk=
github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk=
github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
github.com/agext/levenshtein v1.2.3 h1:YB2fHEn0UJagG8T1rrWknE3ZQzWM06O8AMAatNn7lmo=
Expand Down
3 changes: 3 additions & 0 deletions internal/provider/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@ type AblyNamespace struct {
PushEnabled types.Bool `tfsdk:"push_enabled"`
TlsOnly types.Bool `tfsdk:"tls_only"`
ExposeTimeserial types.Bool `tfsdk:"expose_timeserial"`
BatchingEnabled types.Bool `tfsdk:"batching_enabled"`
BatchingPolicy types.String `tfsdk:"batching_policy"`
BatchingInterval types.Int64 `tfsdk:"batching_interval"`
}

// Ably Key
Expand Down
66 changes: 66 additions & 0 deletions internal/provider/resource_ably_namespace.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,33 @@ func (r resourceNamespace) GetSchema(_ context.Context) (tfsdk.Schema, diag.Diag
DefaultAttribute(types.BoolValue(false)),
},
},
"batching_enabled": {
Type: types.BoolType,
Optional: true,
Computed: true,
Description: "If true, channels within this namespace will start batching inbound messages instead of sending them out immediately to subscribers as per the configured policy.",
PlanModifiers: []tfsdk.AttributePlanModifier{
DefaultAttribute(types.BoolValue(false)),
},
},
"batching_policy": {
Type: types.StringType,
Optional: true,
Computed: true,
Description: "When configured, sets the policy for message batching.",
PlanModifiers: []tfsdk.AttributePlanModifier{
DefaultAttribute(types.StringValue("")),
},
},
"batching_interval": {
Type: types.Int64Type,
Optional: true,
Computed: true,
Description: "When configured, sets the maximium batching interval in the channel.",
PlanModifiers: []tfsdk.AttributePlanModifier{
DefaultAttribute(types.Int64Null()),
},
},
},
MarkdownDescription: "The ably_namespace resource allows you to manage namespaces for channel rules in Ably. Read more in the Ably documentation: https://ably.com/docs/general/channel-rules-namespaces.",
}, nil
Expand Down Expand Up @@ -123,6 +150,12 @@ func (r resourceNamespace) Create(ctx context.Context, req tfsdk_resource.Create
ExposeTimeserial: plan.ExposeTimeserial.ValueBool(),
}

if plan.BatchingEnabled.ValueBool() {
namespace_values.BatchingEnabled = true
namespace_values.BatchingPolicy = plan.BatchingPolicy.ValueString()
namespace_values.BatchingInterval = ably_control_go.BatchingInterval(int(plan.BatchingInterval.ValueInt64()))
}

// Creates a new Ably namespace by invoking the CreateNamespace function from the Client Library
ably_namespace, err := r.p.client.CreateNamespace(plan.AppID.ValueString(), &namespace_values)
if err != nil {
Expand All @@ -133,6 +166,12 @@ func (r resourceNamespace) Create(ctx context.Context, req tfsdk_resource.Create
return
}

// Handle the pointer gracefully
batchingInterval := types.Int64Null()
if ably_namespace.BatchingInterval != nil {
batchingInterval = types.Int64Value(int64(*ably_namespace.BatchingInterval))
}

// Maps response body to resource schema attributes.
resp_apps := AblyNamespace{
AppID: types.StringValue(plan.AppID.ValueString()),
Expand All @@ -143,6 +182,9 @@ func (r resourceNamespace) Create(ctx context.Context, req tfsdk_resource.Create
PushEnabled: types.BoolValue(ably_namespace.PushEnabled),
TlsOnly: types.BoolValue(ably_namespace.TlsOnly),
ExposeTimeserial: types.BoolValue(namespace_values.ExposeTimeserial),
BatchingEnabled: types.BoolValue(ably_namespace.BatchingEnabled),
BatchingPolicy: types.StringValue(ably_namespace.BatchingPolicy),
BatchingInterval: batchingInterval,
}

// Sets state for the new Ably App.
Expand Down Expand Up @@ -191,6 +233,12 @@ func (r resourceNamespace) Read(ctx context.Context, req tfsdk_resource.ReadRequ
// Loops through namespaces and if id matches, sets state.
for _, v := range namespaces {
if v.ID == namespace_id {
// Handle the pointer gracefully
batchingInterval := types.Int64Null()
if v.BatchingInterval != nil {
batchingInterval = types.Int64Value(int64(*v.BatchingInterval))
}

resp_namespaces := AblyNamespace{
AppID: types.StringValue(app_id),
ID: types.StringValue(namespace_id),
Expand All @@ -200,6 +248,9 @@ func (r resourceNamespace) Read(ctx context.Context, req tfsdk_resource.ReadRequ
PushEnabled: types.BoolValue(v.PushEnabled),
TlsOnly: types.BoolValue(v.TlsOnly),
ExposeTimeserial: types.BoolValue(v.ExposeTimeserial),
BatchingEnabled: types.BoolValue(v.BatchingEnabled),
BatchingPolicy: types.StringValue(v.BatchingPolicy),
BatchingInterval: batchingInterval,
}
// Sets state to namespace values.
diags = resp.State.Set(ctx, &resp_namespaces)
Expand Down Expand Up @@ -243,6 +294,12 @@ func (r resourceNamespace) Update(ctx context.Context, req tfsdk_resource.Update
ExposeTimeserial: plan.ExposeTimeserial.ValueBool(),
}

if plan.BatchingEnabled.ValueBool() {
namespace_values.BatchingEnabled = true
namespace_values.BatchingPolicy = plan.BatchingPolicy.ValueString()
namespace_values.BatchingInterval = ably_control_go.BatchingInterval(int(plan.BatchingInterval.ValueInt64()))
}

// Updates an Ably Namespace. The function invokes the Client Library UpdateNamespace method.
ably_namespace, err := r.p.client.UpdateNamespace(app_id, &namespace_values)
if err != nil {
Expand All @@ -253,6 +310,12 @@ func (r resourceNamespace) Update(ctx context.Context, req tfsdk_resource.Update
return
}

// Handle the pointer gracefully
batchingInterval := types.Int64Null()
if ably_namespace.BatchingInterval != nil {
batchingInterval = types.Int64Value(int64(*ably_namespace.BatchingInterval))
}

resp_namespaces := AblyNamespace{
AppID: types.StringValue(app_id),
ID: types.StringValue(ably_namespace.ID),
Expand All @@ -262,6 +325,9 @@ func (r resourceNamespace) Update(ctx context.Context, req tfsdk_resource.Update
PushEnabled: types.BoolValue(ably_namespace.PushEnabled),
TlsOnly: types.BoolValue(ably_namespace.TlsOnly),
ExposeTimeserial: types.BoolValue(ably_namespace.ExposeTimeserial),
BatchingEnabled: types.BoolValue(ably_namespace.BatchingEnabled),
BatchingPolicy: types.StringValue(ably_namespace.BatchingPolicy),
BatchingInterval: batchingInterval,
}

// Sets state to new namespace.
Expand Down
66 changes: 65 additions & 1 deletion internal/provider/resource_ably_namespace_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,33 @@ func TestAccAblyNamespace(t *testing.T) {
resource.TestCheckResourceAttr("ably_namespace.namespace0", "expose_timeserial", "false"),
),
},
{
Config: testAccAblyNamespaceBatchingConfig(app_name, ably_control_go.Namespace{
ID: namespace_name + "batching",
Authenticated: false,
Persisted: false,
PersistLast: false,
PushEnabled: false,
TlsOnly: false,
ExposeTimeserial: false,
BatchingEnabled: true,
BatchingPolicy: "some-policy",
BatchingInterval: ably_control_go.BatchingInterval(100),
}),
Check: resource.ComposeAggregateTestCheckFunc(
resource.TestCheckResourceAttr("ably_app.app0", "name", app_name),
resource.TestCheckResourceAttr("ably_namespace.namespace0", "id", namespace_name+"batching"),
resource.TestCheckResourceAttr("ably_namespace.namespace0", "authenticated", "false"),
resource.TestCheckResourceAttr("ably_namespace.namespace0", "persisted", "false"),
resource.TestCheckResourceAttr("ably_namespace.namespace0", "persist_last", "false"),
resource.TestCheckResourceAttr("ably_namespace.namespace0", "push_enabled", "false"),
resource.TestCheckResourceAttr("ably_namespace.namespace0", "tls_only", "false"),
resource.TestCheckResourceAttr("ably_namespace.namespace0", "expose_timeserial", "false"),
resource.TestCheckResourceAttr("ably_namespace.namespace0", "batching_enabled", "true"),
resource.TestCheckResourceAttr("ably_namespace.namespace0", "batching_policy", "some-policy"),
resource.TestCheckResourceAttr("ably_namespace.namespace0", "batching_interval", "100"),
),
},
// Delete testing automatically occurs in TestCase
},
})
Expand All @@ -97,7 +124,7 @@ terraform {
}
}
}
# You can provide your Ably Token & URL inline or use environment variables ABLY_ACCOUNT_TOKEN & ABLY_URL
provider "ably" {}
Expand All @@ -120,3 +147,40 @@ resource "ably_namespace" "namespace0" {
`, appName, namespace.ID, namespace.Authenticated, namespace.Persisted, namespace.PersistLast, namespace.PushEnabled, namespace.TlsOnly, namespace.ExposeTimeserial)
}

func testAccAblyNamespaceBatchingConfig(appName string, namespace ably_control_go.Namespace) string {
return fmt.Sprintf(`
terraform {
required_providers {
ably = {
source = "github.com/ably/ably"
version = "0.4.3"
}
}
}
# You can provide your Ably Token & URL inline or use environment variables ABLY_ACCOUNT_TOKEN & ABLY_URL
provider "ably" {}
resource "ably_app" "app0" {
name = %[1]q
status = "enabled"
tls_only = true
}
resource "ably_namespace" "namespace0" {
app_id = ably_app.app0.id
id = %[2]q
authenticated = %[3]t
persisted = %[4]t
persist_last = %[5]t
push_enabled = %[6]t
tls_only = %[7]t
expose_timeserial = %[8]t
batching_enabled = %[9]t
batching_policy = "%[10]s"
batching_interval = %[11]d
}
`, appName, namespace.ID, namespace.Authenticated, namespace.Persisted, namespace.PersistLast, namespace.PushEnabled, namespace.TlsOnly, namespace.ExposeTimeserial, namespace.BatchingEnabled, namespace.BatchingPolicy, *namespace.BatchingInterval)
}

0 comments on commit 9ca554f

Please sign in to comment.