sg-event-daemon 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. sg_event_daemon-0.1.0/.gitignore +46 -0
  2. sg_event_daemon-0.1.0/LICENSE +21 -0
  3. sg_event_daemon-0.1.0/PKG-INFO +224 -0
  4. sg_event_daemon-0.1.0/README.md +197 -0
  5. sg_event_daemon-0.1.0/docs/operations.md +683 -0
  6. sg_event_daemon-0.1.0/docs/porting.md +388 -0
  7. sg_event_daemon-0.1.0/pyproject.toml +169 -0
  8. sg_event_daemon-0.1.0/src/sg_event_daemon/__init__.py +9 -0
  9. sg_event_daemon-0.1.0/src/sg_event_daemon/__main__.py +8 -0
  10. sg_event_daemon-0.1.0/src/sg_event_daemon/_checkpoint.py +236 -0
  11. sg_event_daemon-0.1.0/src/sg_event_daemon/_checkpoint_host.py +226 -0
  12. sg_event_daemon-0.1.0/src/sg_event_daemon/_cli.py +990 -0
  13. sg_event_daemon-0.1.0/src/sg_event_daemon/_config.py +1478 -0
  14. sg_event_daemon-0.1.0/src/sg_event_daemon/_control.py +676 -0
  15. sg_event_daemon-0.1.0/src/sg_event_daemon/_downstream.py +144 -0
  16. sg_event_daemon-0.1.0/src/sg_event_daemon/_event_frame.py +60 -0
  17. sg_event_daemon-0.1.0/src/sg_event_daemon/_events.py +452 -0
  18. sg_event_daemon-0.1.0/src/sg_event_daemon/_fanout.py +868 -0
  19. sg_event_daemon-0.1.0/src/sg_event_daemon/_group_delivery.py +729 -0
  20. sg_event_daemon-0.1.0/src/sg_event_daemon/_group_errors.py +17 -0
  21. sg_event_daemon-0.1.0/src/sg_event_daemon/_group_obligations.py +258 -0
  22. sg_event_daemon-0.1.0/src/sg_event_daemon/_group_recovery.py +2791 -0
  23. sg_event_daemon-0.1.0/src/sg_event_daemon/_group_state.py +1943 -0
  24. sg_event_daemon-0.1.0/src/sg_event_daemon/_group_store.py +341 -0
  25. sg_event_daemon-0.1.0/src/sg_event_daemon/_group_types.py +827 -0
  26. sg_event_daemon-0.1.0/src/sg_event_daemon/_health.py +887 -0
  27. sg_event_daemon-0.1.0/src/sg_event_daemon/_identity.py +68 -0
  28. sg_event_daemon-0.1.0/src/sg_event_daemon/_ipc.py +5035 -0
  29. sg_event_daemon-0.1.0/src/sg_event_daemon/_lane.py +1872 -0
  30. sg_event_daemon-0.1.0/src/sg_event_daemon/_logging.py +402 -0
  31. sg_event_daemon-0.1.0/src/sg_event_daemon/_platform.py +714 -0
  32. sg_event_daemon-0.1.0/src/sg_event_daemon/_plugins.py +1307 -0
  33. sg_event_daemon-0.1.0/src/sg_event_daemon/_probe.py +595 -0
  34. sg_event_daemon-0.1.0/src/sg_event_daemon/_providers.py +376 -0
  35. sg_event_daemon-0.1.0/src/sg_event_daemon/_resources.py +66 -0
  36. sg_event_daemon-0.1.0/src/sg_event_daemon/_source.py +2484 -0
  37. sg_event_daemon-0.1.0/src/sg_event_daemon/_source_obligations.py +652 -0
  38. sg_event_daemon-0.1.0/src/sg_event_daemon/_source_schema.py +338 -0
  39. sg_event_daemon-0.1.0/src/sg_event_daemon/_source_state.py +1095 -0
  40. sg_event_daemon-0.1.0/src/sg_event_daemon/_source_store.py +1293 -0
  41. sg_event_daemon-0.1.0/src/sg_event_daemon/_sqlite.py +394 -0
  42. sg_event_daemon-0.1.0/src/sg_event_daemon/_state_paths.py +71 -0
  43. sg_event_daemon-0.1.0/src/sg_event_daemon/_strict.py +1193 -0
  44. sg_event_daemon-0.1.0/src/sg_event_daemon/_supervisor.py +5859 -0
  45. sg_event_daemon-0.1.0/src/sg_event_daemon/_watchdog.py +337 -0
  46. sg_event_daemon-0.1.0/src/sg_event_daemon/_worker.py +5519 -0
  47. sg_event_daemon-0.1.0/src/sg_event_daemon/_write_lock.py +551 -0
  48. sg_event_daemon-0.1.0/src/sg_event_daemon/py.typed +0 -0
  49. sg_event_daemon-0.1.0/src/sg_event_daemon/testing.py +639 -0
@@ -0,0 +1,46 @@
1
+ # Byte-compiled / optimized / DLL files
2
+ __pycache__/
3
+ *.py[cod]
4
+ *$py.class
5
+
6
+ # C extensions
7
+ *.so
8
+
9
+ # Distribution / packaging
10
+ .Python
11
+ build/
12
+ dist/
13
+ .eggs/
14
+ *.egg-info/
15
+ *.egg
16
+
17
+ # Virtual environments
18
+ .venv/
19
+ venv/
20
+ ENV/
21
+
22
+ # PyInstaller
23
+ *.manifest
24
+ *.spec
25
+
26
+ # Unit test / coverage reports
27
+ htmlcov/
28
+ .tox/
29
+ .nox/
30
+ .coverage*
31
+ .pytest_cache/
32
+ .cache/
33
+
34
+ # Type checker / linter caches
35
+ .pyright/
36
+ .mypy_cache/
37
+ .ruff_cache/
38
+ pyrightconfig.json
39
+
40
+ # Editors
41
+ .vscode/
42
+ .idea/
43
+
44
+ # OS
45
+ .DS_Store
46
+ Thumbs.db
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 the sg-event-daemon authors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
@@ -0,0 +1,224 @@
1
+ Metadata-Version: 2.5
2
+ Name: sg-event-daemon
3
+ Version: 0.1.0
4
+ Summary: Event daemon for Autodesk Flow Production Tracking
5
+ Project-URL: Documentation, https://github.com/dactylo/sg-event-daemon/tree/main/docs
6
+ Project-URL: Homepage, https://github.com/dactylo/sg-event-daemon
7
+ Project-URL: Issues, https://github.com/dactylo/sg-event-daemon/issues
8
+ Project-URL: Repository, https://github.com/dactylo/sg-event-daemon
9
+ License-Expression: MIT
10
+ License-File: LICENSE
11
+ Keywords: daemon,events,flow-production-tracking,shotgrid,shotgun
12
+ Classifier: Programming Language :: Python :: 3 :: Only
13
+ Classifier: Programming Language :: Python :: 3.11
14
+ Classifier: Programming Language :: Python :: 3.12
15
+ Classifier: Programming Language :: Python :: 3.13
16
+ Classifier: Programming Language :: Python :: 3.14
17
+ Classifier: Programming Language :: Python :: 3.15
18
+ Classifier: Typing :: Typed
19
+ Requires-Python: >=3.11
20
+ Provides-Extra: sg-python-api
21
+ Requires-Dist: sg-python-api<0.2,>=0.1; extra == 'sg-python-api'
22
+ Provides-Extra: sg-python-api-async
23
+ Requires-Dist: sg-python-api[async]<0.2,>=0.1; extra == 'sg-python-api-async'
24
+ Provides-Extra: shotgun-api3
25
+ Requires-Dist: shotgun-api3<4,>=3.10; extra == 'shotgun-api3'
26
+ Description-Content-Type: text/markdown
27
+
28
+ # sg-event-daemon
29
+
30
+ sg-event-daemon runs your Python plugins in response to Autodesk Flow Production Tracking events.
31
+ It watches `EventLogEntry` records, delivers each event to the plugins that want it, and records
32
+ delivery progress in SQLite. After a crash or restart it resumes where it stopped, including an
33
+ event whose callbacks had only partly finished.
34
+
35
+ It is for pipeline teams whose event-driven integrations need controlled recovery and health
36
+ checks. One foreground supervisor can serve several sites and plugin groups. Groups can share one
37
+ event poller while keeping separate ordering, failure handling, and recovery, so a failing plugin
38
+ stops only its own group.
39
+
40
+ This documentation uses SG for Flow Production Tracking, formerly named Shotgun and ShotGrid.
41
+
42
+ ## Why use it?
43
+
44
+ The first-party [shotgunEvents](https://github.com/shotgunsoftware/shotgunevents) daemon remains a
45
+ good fit for existing plugins and simple deployments. It loads its plugins directly, reloads
46
+ changed plugin files, daemonizes itself, and can send logs to files and email. sg-event-daemon
47
+ makes different tradeoffs:
48
+
49
+ | Need | sg-event-daemon behavior |
50
+ | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
51
+ | Recover after a crash | Records its position, the event in progress, and each completed callback in SQLite. Event contents are refetched from SG, not stored. |
52
+ | Isolate workloads | Polls each event source once for any number of plugin groups. Each group delivers serially and fails independently. |
53
+ | Control ordering | Offers low-latency `eager` delivery, or `strict` delivery in increasing event ID order at the cost of a holdback delay. |
54
+ | Operate failures | Provides status and health probes, callback deadlines, worker restart limits, and audited recovery commands. |
55
+ | Write modern plugins | Runs synchronous callbacks, and native asynchronous callbacks with the `sg-python-api-async` extra. |
56
+
57
+ Weigh these limits before you adopt it:
58
+
59
+ - shotgunEvents plugins do not run unmodified. Port each one to explicit registration, as the
60
+ [porting guide](https://github.com/dactylo/sg-event-daemon/blob/v0.1.0/docs/porting.md) shows.
61
+ - A new plugin group starts at the latest visible event. The daemon does not import the event
62
+ position saved by shotgunEvents.
63
+ - Plugin files are not reloaded while the daemon runs. Restart the daemon to load changed plugin
64
+ code.
65
+ - The daemon runs in the foreground. A service manager such as systemd or Kubernetes owns process
66
+ restarts, log capture, and alerts.
67
+ - Delivery is at least once. A callback can run again after a crash, retry, or replay, so its side
68
+ effects must tolerate repetition.
69
+
70
+ ## Installation
71
+
72
+ You need:
73
+
74
+ - Linux or macOS.
75
+ - Python 3.11 or newer whose SQLite library is version 3.51.3 or newer. The daemon checks the
76
+ SQLite version before it opens state.
77
+ - Exactly one SG API provider. `shotgun-api3` supports synchronous groups; `sg-python-api` supports
78
+ synchronous and asynchronous groups.
79
+ - An SG site and script credentials that can read events and perform your plugins' work.
80
+ - A private, persistent state directory on local storage, owned by the user that runs the daemon.
81
+
82
+ From a checkout, install the command with [uv](https://docs.astral.sh/uv/) and the standard
83
+ Autodesk `shotgun-api3` provider:
84
+
85
+ ```sh
86
+ uv tool install '.[shotgun-api3]'
87
+ ```
88
+
89
+ To use the `sg-python-api` provider instead, install the `sg-python-api` extra for synchronous
90
+ groups or the `sg-python-api-async` extra for asynchronous groups. Install only one provider: both
91
+ supply the `shotgun_api3` module, and the daemon refuses to run when both are present.
92
+
93
+ Python's version alone does not determine its SQLite version. Check the SQLite library in the
94
+ installed tool's environment:
95
+
96
+ ```sh
97
+ "$(uv tool dir)/sg-event-daemon/bin/python" -c 'import sqlite3; print(sqlite3.sqlite_version)'
98
+ ```
99
+
100
+ ## Quick start
101
+
102
+ This example sets up one plugin that logs each new event, then starts the daemon in the foreground.
103
+
104
+ ### Write a plugin
105
+
106
+ Save this plugin as `/etc/sg-event-daemon/plugins/observe.py`:
107
+
108
+ ```python
109
+ def on_event(context):
110
+ context.logger.info('EventLogEntry %s', context.event['id'])
111
+
112
+
113
+ def register(registrar):
114
+ registrar.add_callback(id='log-event', callback=on_event)
115
+ ```
116
+
117
+ ### Configure the daemon
118
+
119
+ Save this configuration as `/etc/sg-event-daemon/daemon.toml`, replacing the site URL and script
120
+ name with your own:
121
+
122
+ ```toml
123
+ [daemon]
124
+ state_dir = "/var/lib/sg-event-daemon"
125
+ sg_api_provider = "shotgun-api3"
126
+
127
+ [sites.studio]
128
+ server = "https://studio.example.invalid"
129
+ default_source = "primary"
130
+
131
+ [sites.studio.credentials.event-reader]
132
+ script_name = "event-daemon-reader"
133
+ api_key = { env = "SG_EVENT_READER_KEY" }
134
+
135
+ [sites.studio.sources.primary]
136
+ credentials = "event-reader"
137
+
138
+ [sites.studio.groups.observers]
139
+ source = "primary"
140
+ callback_credentials = "event-reader"
141
+ execution = "sync"
142
+
143
+ [[sites.studio.groups.observers.plugins]]
144
+ id = "event-log"
145
+ path = "plugins/observe.py"
146
+ ```
147
+
148
+ The script key comes from the `SG_EVENT_READER_KEY` environment variable, so the configuration file
149
+ holds no secrets. Relative plugin paths and `state_dir` resolve from the directory of the
150
+ configuration file after symlinks are resolved. If `state_dir` is missing, the daemon creates it,
151
+ which requires write access to its parent. The directory must be owned by the daemon's user with
152
+ mode `0700`.
153
+
154
+ ### Validate and start
155
+
156
+ With `SG_EVENT_READER_KEY` set in the environment, validate the configuration and plugin, then
157
+ start the supervisor:
158
+
159
+ ```sh
160
+ sg-event-daemon validate-config --config /etc/sg-event-daemon/daemon.toml
161
+ sg-event-daemon supervise --config /etc/sg-event-daemon/daemon.toml
162
+ ```
163
+
164
+ Validation imports the plugin without contacting SG. It warns that importing plugin code can have
165
+ side effects, then prints `{"provider":"shotgun-api3","sites":["studio"],"validated":true}`.
166
+ Invalid configuration, including a missing plugin file, makes either command print `error:` and
167
+ exit with status 2. Invalid plugin registration makes `validate-config` exit with status 2. During
168
+ `supervise`, a plugin import or registration failure stops its worker; the supervisor restarts that
169
+ worker until its breaker opens.
170
+
171
+ The supervisor runs until you stop it with Ctrl-C or SIGTERM, which shuts down its workers and
172
+ exits with status 0. The new group starts at the latest visible event rather than processing
173
+ existing history. When someone changes something in SG, the supervisor's output shows an
174
+ `EventLogEntry` line from the plugin.
175
+
176
+ ### Check status
177
+
178
+ In another shell, ask the running supervisor for its status:
179
+
180
+ ```sh
181
+ sg-event-daemon status --config /etc/sg-event-daemon/daemon.toml
182
+ ```
183
+
184
+ The command prints one line of JSON. `primary_state` summarizes overall health, for example `idle`
185
+ while the group waits for events, and `liveness` and `readiness` report the health checks. If no
186
+ supervisor is running for that state directory, the command prints one line that starts with
187
+ `error:` and exits with status 3.
188
+
189
+ This example only logs events. A plugin that writes to SG should use separate callback credentials
190
+ with the permissions it needs; see
191
+ [separate reader and writer credentials](https://github.com/dactylo/sg-event-daemon/blob/v0.1.0/docs/operations.md#separate-reader-and-writer-credentials).
192
+
193
+ ## Documentation
194
+
195
+ | If you want to... | Read |
196
+ | ---------------------------------------------- | ------------------------------------------------------------------------ |
197
+ | Port a shotgunEvents plugin or write a new one | [Porting plugins](https://github.com/dactylo/sg-event-daemon/blob/v0.1.0/docs/porting.md) |
198
+ | Test a plugin without a daemon or SG site | [Offline harness](https://github.com/dactylo/sg-event-daemon/blob/v0.1.0/docs/porting.md#test-plugins-offline) |
199
+ | Give plugins separate credentials for writing | [Credentials](https://github.com/dactylo/sg-event-daemon/blob/v0.1.0/docs/operations.md#separate-reader-and-writer-credentials) |
200
+ | Choose between eager and strict ordering | [Ordering](https://github.com/dactylo/sg-event-daemon/blob/v0.1.0/docs/operations.md#choose-eager-or-strict-ordering) |
201
+ | Monitor health or configure probes | [Status and probes](https://github.com/dactylo/sg-event-daemon/blob/v0.1.0/docs/operations.md#check-status-and-health) |
202
+ | Recover a failed or stopped group | [Recovery](https://github.com/dactylo/sg-event-daemon/blob/v0.1.0/docs/operations.md#recover-a-group-or-source) |
203
+ | Back up state or plan storage | [State and backups](https://github.com/dactylo/sg-event-daemon/blob/v0.1.0/docs/operations.md#sqlite-state-and-backups) |
204
+ | Run on Kubernetes | [Kubernetes](https://github.com/dactylo/sg-event-daemon/blob/v0.1.0/docs/operations.md#kubernetes) |
205
+ | Size queues, buffers, and memory | [Capacity](https://github.com/dactylo/sg-event-daemon/blob/v0.1.0/docs/operations.md#capacity) |
206
+ | See changes by version | [Changelog](https://github.com/dactylo/sg-event-daemon/blob/v0.1.0/CHANGELOG.md) |
207
+
208
+ ## Development
209
+
210
+ See the [development guide](https://github.com/dactylo/sg-event-daemon/blob/v0.1.0/docs/development.md) for the required tools, CI, and dependency locks.
211
+ With those tools installed, run:
212
+
213
+ ```sh
214
+ make setup
215
+ make check
216
+ ```
217
+
218
+ The checks never contact a live SG site; the development guide describes the opt-in live tests.
219
+
220
+ ## License
221
+
222
+ sg-event-daemon is available under the [MIT License](https://github.com/dactylo/sg-event-daemon/blob/v0.1.0/LICENSE). It is an independent project and is
223
+ not affiliated with or endorsed by Autodesk. Flow Production Tracking is a product of Autodesk,
224
+ Inc.
@@ -0,0 +1,197 @@
1
+ # sg-event-daemon
2
+
3
+ sg-event-daemon runs your Python plugins in response to Autodesk Flow Production Tracking events.
4
+ It watches `EventLogEntry` records, delivers each event to the plugins that want it, and records
5
+ delivery progress in SQLite. After a crash or restart it resumes where it stopped, including an
6
+ event whose callbacks had only partly finished.
7
+
8
+ It is for pipeline teams whose event-driven integrations need controlled recovery and health
9
+ checks. One foreground supervisor can serve several sites and plugin groups. Groups can share one
10
+ event poller while keeping separate ordering, failure handling, and recovery, so a failing plugin
11
+ stops only its own group.
12
+
13
+ This documentation uses SG for Flow Production Tracking, formerly named Shotgun and ShotGrid.
14
+
15
+ ## Why use it?
16
+
17
+ The first-party [shotgunEvents](https://github.com/shotgunsoftware/shotgunevents) daemon remains a
18
+ good fit for existing plugins and simple deployments. It loads its plugins directly, reloads
19
+ changed plugin files, daemonizes itself, and can send logs to files and email. sg-event-daemon
20
+ makes different tradeoffs:
21
+
22
+ | Need | sg-event-daemon behavior |
23
+ | --------------------- | ------------------------------------------------------------------------------------------------------------------------------------- |
24
+ | Recover after a crash | Records its position, the event in progress, and each completed callback in SQLite. Event contents are refetched from SG, not stored. |
25
+ | Isolate workloads | Polls each event source once for any number of plugin groups. Each group delivers serially and fails independently. |
26
+ | Control ordering | Offers low-latency `eager` delivery, or `strict` delivery in increasing event ID order at the cost of a holdback delay. |
27
+ | Operate failures | Provides status and health probes, callback deadlines, worker restart limits, and audited recovery commands. |
28
+ | Write modern plugins | Runs synchronous callbacks, and native asynchronous callbacks with the `sg-python-api-async` extra. |
29
+
30
+ Weigh these limits before you adopt it:
31
+
32
+ - shotgunEvents plugins do not run unmodified. Port each one to explicit registration, as the
33
+ [porting guide](docs/porting.md) shows.
34
+ - A new plugin group starts at the latest visible event. The daemon does not import the event
35
+ position saved by shotgunEvents.
36
+ - Plugin files are not reloaded while the daemon runs. Restart the daemon to load changed plugin
37
+ code.
38
+ - The daemon runs in the foreground. A service manager such as systemd or Kubernetes owns process
39
+ restarts, log capture, and alerts.
40
+ - Delivery is at least once. A callback can run again after a crash, retry, or replay, so its side
41
+ effects must tolerate repetition.
42
+
43
+ ## Installation
44
+
45
+ You need:
46
+
47
+ - Linux or macOS.
48
+ - Python 3.11 or newer whose SQLite library is version 3.51.3 or newer. The daemon checks the
49
+ SQLite version before it opens state.
50
+ - Exactly one SG API provider. `shotgun-api3` supports synchronous groups; `sg-python-api` supports
51
+ synchronous and asynchronous groups.
52
+ - An SG site and script credentials that can read events and perform your plugins' work.
53
+ - A private, persistent state directory on local storage, owned by the user that runs the daemon.
54
+
55
+ From a checkout, install the command with [uv](https://docs.astral.sh/uv/) and the standard
56
+ Autodesk `shotgun-api3` provider:
57
+
58
+ ```sh
59
+ uv tool install '.[shotgun-api3]'
60
+ ```
61
+
62
+ To use the `sg-python-api` provider instead, install the `sg-python-api` extra for synchronous
63
+ groups or the `sg-python-api-async` extra for asynchronous groups. Install only one provider: both
64
+ supply the `shotgun_api3` module, and the daemon refuses to run when both are present.
65
+
66
+ Python's version alone does not determine its SQLite version. Check the SQLite library in the
67
+ installed tool's environment:
68
+
69
+ ```sh
70
+ "$(uv tool dir)/sg-event-daemon/bin/python" -c 'import sqlite3; print(sqlite3.sqlite_version)'
71
+ ```
72
+
73
+ ## Quick start
74
+
75
+ This example sets up one plugin that logs each new event, then starts the daemon in the foreground.
76
+
77
+ ### Write a plugin
78
+
79
+ Save this plugin as `/etc/sg-event-daemon/plugins/observe.py`:
80
+
81
+ ```python
82
+ def on_event(context):
83
+ context.logger.info('EventLogEntry %s', context.event['id'])
84
+
85
+
86
+ def register(registrar):
87
+ registrar.add_callback(id='log-event', callback=on_event)
88
+ ```
89
+
90
+ ### Configure the daemon
91
+
92
+ Save this configuration as `/etc/sg-event-daemon/daemon.toml`, replacing the site URL and script
93
+ name with your own:
94
+
95
+ ```toml
96
+ [daemon]
97
+ state_dir = "/var/lib/sg-event-daemon"
98
+ sg_api_provider = "shotgun-api3"
99
+
100
+ [sites.studio]
101
+ server = "https://studio.example.invalid"
102
+ default_source = "primary"
103
+
104
+ [sites.studio.credentials.event-reader]
105
+ script_name = "event-daemon-reader"
106
+ api_key = { env = "SG_EVENT_READER_KEY" }
107
+
108
+ [sites.studio.sources.primary]
109
+ credentials = "event-reader"
110
+
111
+ [sites.studio.groups.observers]
112
+ source = "primary"
113
+ callback_credentials = "event-reader"
114
+ execution = "sync"
115
+
116
+ [[sites.studio.groups.observers.plugins]]
117
+ id = "event-log"
118
+ path = "plugins/observe.py"
119
+ ```
120
+
121
+ The script key comes from the `SG_EVENT_READER_KEY` environment variable, so the configuration file
122
+ holds no secrets. Relative plugin paths and `state_dir` resolve from the directory of the
123
+ configuration file after symlinks are resolved. If `state_dir` is missing, the daemon creates it,
124
+ which requires write access to its parent. The directory must be owned by the daemon's user with
125
+ mode `0700`.
126
+
127
+ ### Validate and start
128
+
129
+ With `SG_EVENT_READER_KEY` set in the environment, validate the configuration and plugin, then
130
+ start the supervisor:
131
+
132
+ ```sh
133
+ sg-event-daemon validate-config --config /etc/sg-event-daemon/daemon.toml
134
+ sg-event-daemon supervise --config /etc/sg-event-daemon/daemon.toml
135
+ ```
136
+
137
+ Validation imports the plugin without contacting SG. It warns that importing plugin code can have
138
+ side effects, then prints `{"provider":"shotgun-api3","sites":["studio"],"validated":true}`.
139
+ Invalid configuration, including a missing plugin file, makes either command print `error:` and
140
+ exit with status 2. Invalid plugin registration makes `validate-config` exit with status 2. During
141
+ `supervise`, a plugin import or registration failure stops its worker; the supervisor restarts that
142
+ worker until its breaker opens.
143
+
144
+ The supervisor runs until you stop it with Ctrl-C or SIGTERM, which shuts down its workers and
145
+ exits with status 0. The new group starts at the latest visible event rather than processing
146
+ existing history. When someone changes something in SG, the supervisor's output shows an
147
+ `EventLogEntry` line from the plugin.
148
+
149
+ ### Check status
150
+
151
+ In another shell, ask the running supervisor for its status:
152
+
153
+ ```sh
154
+ sg-event-daemon status --config /etc/sg-event-daemon/daemon.toml
155
+ ```
156
+
157
+ The command prints one line of JSON. `primary_state` summarizes overall health, for example `idle`
158
+ while the group waits for events, and `liveness` and `readiness` report the health checks. If no
159
+ supervisor is running for that state directory, the command prints one line that starts with
160
+ `error:` and exits with status 3.
161
+
162
+ This example only logs events. A plugin that writes to SG should use separate callback credentials
163
+ with the permissions it needs; see
164
+ [separate reader and writer credentials](docs/operations.md#separate-reader-and-writer-credentials).
165
+
166
+ ## Documentation
167
+
168
+ | If you want to... | Read |
169
+ | ---------------------------------------------- | ------------------------------------------------------------------------ |
170
+ | Port a shotgunEvents plugin or write a new one | [Porting plugins](docs/porting.md) |
171
+ | Test a plugin without a daemon or SG site | [Offline harness](docs/porting.md#test-plugins-offline) |
172
+ | Give plugins separate credentials for writing | [Credentials](docs/operations.md#separate-reader-and-writer-credentials) |
173
+ | Choose between eager and strict ordering | [Ordering](docs/operations.md#choose-eager-or-strict-ordering) |
174
+ | Monitor health or configure probes | [Status and probes](docs/operations.md#check-status-and-health) |
175
+ | Recover a failed or stopped group | [Recovery](docs/operations.md#recover-a-group-or-source) |
176
+ | Back up state or plan storage | [State and backups](docs/operations.md#sqlite-state-and-backups) |
177
+ | Run on Kubernetes | [Kubernetes](docs/operations.md#kubernetes) |
178
+ | Size queues, buffers, and memory | [Capacity](docs/operations.md#capacity) |
179
+ | See changes by version | [Changelog](CHANGELOG.md) |
180
+
181
+ ## Development
182
+
183
+ See the [development guide](docs/development.md) for the required tools, CI, and dependency locks.
184
+ With those tools installed, run:
185
+
186
+ ```sh
187
+ make setup
188
+ make check
189
+ ```
190
+
191
+ The checks never contact a live SG site; the development guide describes the opt-in live tests.
192
+
193
+ ## License
194
+
195
+ sg-event-daemon is available under the [MIT License](LICENSE). It is an independent project and is
196
+ not affiliated with or endorsed by Autodesk. Flow Production Tracking is a product of Autodesk,
197
+ Inc.