There might not be an out-of-the-box solution for this workflow, but it can be configured by tracking the lock status of each record. I asked AI and it phrased a solution with far more details than I would have:
Concurrency Control Patterns in Foundry Workshop
1. Optimistic vs. Pessimistic Locking: Why Pessimistic is Needed Here
-
Optimistic Locking is often supported via timestamp/version checks on save (detecting conflicts), but does not actively prevent simultaneous edits.
-
Pessimistic Locking, which is your goal, explicitly marks a record as “locked” and prevents other session(s) from editing.
Workshop (unlike OSDK backend or Slate) can’t natively enforce field- or row-level locks, but you can build this with a few core patterns.
Recommended Approach: Implementing Pessimistic Record Locking in Workshop
A. Create a “Locks” Table
-
Make a new Workshop table (or add columns to your “requests” table) to track lock status.
-
request_id (foreign key to your main record)
-
locked_by (username or user ID)
-
locked_at (timestamp)
-
lock_expires_at (optional, for timeout auto-expiry)
-
B. Lock Acquisition Workflow
-
On “Edit” Request:
-
When a user wants to edit, check the Locks table for this request:
-
If locked_by is blank or expired, allow the user to acquire the lock:
-
Write their user ID and a current timestamp into the lock.
-
Optionally, set an expiry (e.g., +15min).
-
-
If locked by someone else and not expired:
-
Show a UI banner: “This request is currently being edited by [user].”
-
Disable editing.
-
-
-
-
Concurrency Reinforcement:
- All edit actions (writes) should check the Locks table to confirm active lock ownership before committing changes.
C. Lock Release Patterns
-
Explicit Release: When user clicks “Save” or “Cancel,” clear the lock (delete row or null out owner fields).
-
Timeout/Expiration: Periodically check if the lock is old and, if so, consider it expired and reusable.
- Can be implemented by storing
lock_expires_atand checking against current time during edit attempts.
- Can be implemented by storing
-
UI Banner or Indicator: Always show clearly if a lock is in place, including the locking user and how long until expiration.
D. Implementation Tips
-
Atomicity: Use Workshop “actions” for lock acquisition and release to keep the logic clear and reduce race conditions. The write that sets the lock should be atomic.
-
Workshop UI: Use “Conditional Cell Rendering” or “Dynamic Form State” to disable form inputs if a lock is present.
-
Polling/Refreshing: Consider a modest auto-refresh/polling interval on the lock status in the UI for live feedback (every ~10–30 seconds).
-
Edge Cases: Handle users closing their browser/crashing by relying on lock expiration.
Example Schema for a “Locks” Table
| request_id | locked_by | locked_at | lock_expires_at |
|---|---|---|---|
| 1234 | userA@email.com | 2025-12-12 12:00:00 | 2025-12-12 12:15:00 |
| 2345 |
Example UI Logic (Pseudo-Code)
// When editing a request
if (lock for request_id is empty or expired) {
write lock with (request_id, user, now, now + 15min)
allow editing
} else if (lock.locked_by == currentUser) {
allow editing
} else {
show "Locked by [User X] until [expiry]" and disable editing
}
Summary & Practical Recommendations
-
Create a Locks Table: This is your concurrency “source of truth.”
-
Atomic Lock Acquisition: Always check and write the lock as a single atomic update.
-
UI Feedback: Clearly display lock status to users; disable edit controls when locked.
-
Safe Release: Release on save/cancel, or via stale lock expiration.
-
Periodic Refresh: Poll lock status to reflect real-time status changes.
This approach aligns with how many Foundry teams structure collaborative workflows within Workshop’s limits—simple, auditable, and resilient.