Skip to content

Commit

Permalink
docs: Add Component Locking section to README
Browse files Browse the repository at this point in the history
Signed-off-by: Lewis Marshall <lewis.marshall@ably.com>
  • Loading branch information
lmars committed Aug 24, 2023
1 parent e50c3fc commit 7c6136b
Showing 1 changed file with 96 additions and 0 deletions.
96 changes: 96 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,3 +215,99 @@ The above listener will receive a `CursorUpdate` event:
"data": { "color": "red" }
}
```

### Component Locking

Use the Component Locking API to lock stateful components whilst being edited by members to reduce the chances of conflicting changes being made.

Locks are identified using a unique string, and the Spaces SDK maintains that at most one member holds a lock with a given string at any given time.

The Component Locking API supports four operations: Query, Acquire, Release, and Subscribe.

### Query

`space.locks.get` is used to query whether a lock identifier is currently locked and by whom. It returns a `Lock` type which has the following fields:

```typescript
type Lock = {
member: SpaceMember;
request: LockRequest;
};
```

For example:

```javascript
// check if the id is locked
const isLocked = space.locks.get(id) !== undefined;

// check which member has the lock
const { member } = space.locks.get(id);

// check the lock attributes assigned by the member holding the lock
const { request } = space.locks.get(id);
const value = request.attributes.get(key);
```

`space.locks.getAll` returns all lock identifiers which are currently locked as an array of `Lock`:

```javascript
const allLocks = space.locks.getAll();

for (const lock of allLocks) {
// ...
}
```

### Acquire

`space.locks.acquire` initialises a lock request, adds it to the `locks` field of presence message extras, and calls `presence.update`.

It returns a Promise which resolves once `presence.update` resolves.

```javascript
const req = await space.locks.acquire(id);

// or with some attributes
const attributes = new Map();
attributes.set('key', 'value');
const req = await space.locks.acquire(id, { attributes });
```

It throws an error if a lock request already exists for the given identifier with a status of `PENDING` or `LOCKED`.

### Release

`space.locks.release` releases a previously requested lock by removing it from the `locks` field of presence message extras, and calls `presence.update`.

It returns a Promise which resolves once `presence.update` resolves.

```javascript
await space.locks.release(id);
```

### Subscribe

`space.locks.subscribe` subscribes to changes in lock status across all members.

The callback is called with a value of type `Lock`.

```javascript
space.locks.subscribe('update', (lock) => {
// lock.member is the requesting member
// lock.request is the request made by the member
});

// or with destructuring:
space.locks.subscribe('update', ({ member, request }) => {
// request.status is the status of the request, one of PENDING, LOCKED, or UNLOCKED
// request.reason is an ErrorInfo if the status is UNLOCKED
});
```

Such changes occur when:

- a `PENDING` request transitions to `LOCKED` (i.e. the requesting member now holds the lock)
- a `PENDING` request transitions to `UNLOCKED` (i.e. the requesting member does not hold the lock since another member already does)
- a `LOCKED` request transitions to `UNLOCKED` (i.e. the lock was either released or invalidated by a concurrent request which took precedence)
- an `UNLOCKED` request transitions to `LOCKED` (i.e. the requesting member reacquired a lock)

0 comments on commit 7c6136b

Please sign in to comment.