|
| 1 | +import { Tabs } from 'nextra/components' |
| 2 | +import { Callout } from 'nextra/components' |
| 3 | + |
| 4 | +# Writing relationships |
| 5 | + |
| 6 | +This page will provide some practical recommendations for writing relationships to SpiceDB. |
| 7 | +If you are interested in relationships as a concept, check out this [page](/spicedb/concepts/relationships). |
| 8 | + |
| 9 | +## Retries |
| 10 | + |
| 11 | +When making requests to SpiceDB, it's important to implement proper retry logic to handle transient failures. [SpiceDB APIs use gRPC*](/spicedb/getting-started/client-libraries), which can experience various types of temporary failures that can be resolved through retries. |
| 12 | + |
| 13 | +Retries are recommended for all gRPC methods, not just WriteRelationships. |
| 14 | + |
| 15 | +*SpiceDB can also expose an [HTTP API](/spicedb/getting-started/client-libraries#http-clients); however, gRPC is recommended. |
| 16 | + |
| 17 | +### Implementing Retry Policies |
| 18 | + |
| 19 | +You can implement your own retry policies using the gRPC Service Config. |
| 20 | +Below, you will find a recommended Retry Policy. |
| 21 | + |
| 22 | +``` |
| 23 | +"retryPolicy": { |
| 24 | + "maxAttempts": 3, |
| 25 | + "initialBackoff": "1s", |
| 26 | + "maxBackoff": "4s", |
| 27 | + "backoffMultiplier": 2, |
| 28 | + "retryableStatusCodes": [ |
| 29 | + 'UNAVAILABLE', 'RESOURCE_EXHAUSTED', 'DEADLINE_EXCEEDED', 'ABORTED', |
| 30 | + ] |
| 31 | +} |
| 32 | +``` |
| 33 | + |
| 34 | +This retry policy configuration provides exponential backoff with the following behavior: |
| 35 | + |
| 36 | +**`maxAttempts: 3`** - Allows for a maximum of 3 total attempts (1 initial request + 2 retries). |
| 37 | +This prevents infinite retry loops while giving sufficient opportunity for transient issues to resolve. |
| 38 | + |
| 39 | +**`initialBackoff: "1s"`** - Sets the initial delay to 1 second before the first retry attempt. |
| 40 | +This gives the system time to recover from temporary issues. |
| 41 | + |
| 42 | +**`maxBackoff: "4s"`** - Caps the maximum delay between retries at 4 seconds to prevent excessively long waits that could impact user experience. |
| 43 | + |
| 44 | +**`backoffMultiplier: 2`** - Doubles the backoff time with each retry attempt. |
| 45 | +Combined with the other settings, this creates a retry pattern of: 1s → 2s → 4s. |
| 46 | + |
| 47 | +**`retryableStatusCodes`** - Only retries on specific gRPC status codes that indicate transient failures: |
| 48 | +-`UNAVAILABLE`: SpiceDB is temporarily unavailable |
| 49 | +-`RESOURCE_EXHAUSTED`: SpiceDB is overloaded |
| 50 | +-`DEADLINE_EXCEEDED`: Request timed out |
| 51 | +-`ABORTED`: Operation was aborted, often due to conflicts that may resolve on retry |
| 52 | + |
| 53 | +You can find a python retry example [here](https://github.com/authzed/examples/blob/main/data/retry/main.py). |
| 54 | + |
| 55 | +## Writes: Touch vs Create |
| 56 | + |
| 57 | +A SpiceDB [relationship update](https://buf.build/authzed/api/docs/main:authzed.api.v1#authzed.api.v1.RelationshipUpdate) can use one of three operation types `CREATE`, `TOUCH`, OR `DELETE`. |
| 58 | +This section will cover `CREATE` and `TOUCH`. |
| 59 | +You can read more about `DELETE` in [the section below](#deleting-relationships). |
| 60 | + |
| 61 | +### Understanding the Operations |
| 62 | + |
| 63 | +**`CREATE`** - Inserts a new relationship. |
| 64 | +If the relationship already exists, the operation will fail with an error. |
| 65 | + |
| 66 | +**`TOUCH`** - Upserts a relationship. |
| 67 | +If the relationship already exists, it will do nothing. |
| 68 | +If it doesn't exist, it will create it. |
| 69 | + |
| 70 | +### Key Differences |
| 71 | + |
| 72 | +| Operation | Behavior on Existing Relationship | Performance | Use Case | |
| 73 | +|-----------|-----------------------------------|-------------|----------| |
| 74 | +| `CREATE` | Fails with error | Faster (single insert) | Initial relationship creation | |
| 75 | +| `TOUCH` | Updates/overwrites | Slower (delete + insert) | Idempotent operations | |
| 76 | + |
| 77 | +### Special Considerations |
| 78 | + |
| 79 | +**Expiring Relationships:** When working with [expiring relationships](/spicedb/concepts/expiring-relationships), always use `TOUCH`. |
| 80 | +If a relationship has expired but hasn't been garbage collected yet, using `CREATE` will return an error. |
| 81 | + |
| 82 | +**Error Handling:** When using `CREATE`, be prepared to handle duplicate relationship errors appropriately in your application logic. |
| 83 | + |
| 84 | +## Deleting Relationships |
| 85 | + |
| 86 | +SpiceDB provides two methods for deleting relationships: using the `WriteRelationships` API with the `DELETE` operation or using the `DeleteRelationships` API. |
| 87 | +Each approach has different behaviors and use cases. |
| 88 | + |
| 89 | +### WriteRelationships with the `DELETE` Operation |
| 90 | + |
| 91 | +The [`WriteRelationships`](https://buf.build/authzed/api/docs/main:authzed.api.v1#authzed.api.v1.WriteRelationshipsRequest) API supports a `DELETE` operation type that allows you to remove specific relationships as part of a batch of relationship updates. |
| 92 | + |
| 93 | +**`DELETE`** - Removes a relationship. |
| 94 | +If the relationship does not exist, the operation will silently succeed (no-op). |
| 95 | + |
| 96 | +#### Characteristics |
| 97 | + |
| 98 | +- **Atomic Operations**: Can be combined with other relationship operations (`CREATE`, `TOUCH`) in a single atomic transaction |
| 99 | +- **Granular Control**: Delete specific relationships alongside creating or updating others |
| 100 | +- **Silent Failure**: Does not fail if the relationship doesn't exist |
| 101 | +- **Batch Limit**: Subject to the same batch size limits as other `WriteRelationships` operations (1,000 updates by default) |
| 102 | + |
| 103 | +### DeleteRelationships API |
| 104 | + |
| 105 | +The [`DeleteRelationships`](https://buf.build/authzed/api/docs/main:authzed.api.v1#authzed.api.v1.DeleteRelationshipsRequest) API is a dedicated method for bulk deletion of relationships based on filters rather than specifying individual relationships. |
| 106 | + |
| 107 | +#### Characteristics |
| 108 | + |
| 109 | +- **Filter-Based**: Delete relationships based on resource type, relation, subject type, or combinations thereof |
| 110 | +- **Bulk Operations**: Can delete many relationships matching the filter criteria in a single call |
| 111 | +- **Separate Transaction**: Operates independently from `WriteRelationships` |
| 112 | +- **Efficient for Mass Deletion**: Optimized for removing large numbers of relationships |
| 113 | + |
| 114 | +## Bulk Import |
| 115 | + |
| 116 | +Check out [Bulk Importing Relationships](./bulk-operations) |
0 commit comments