@opengeni/db 0.31.1 → 0.36.1
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.
- package/dist/browser-auth.d.ts +209 -1
- package/dist/browser-downloads.d.ts +51 -0
- package/dist/browser-identities.d.ts +11 -2
- package/dist/browser-sessions.d.ts +83 -1
- package/dist/browser-state-artifacts.d.ts +75 -1
- package/dist/canonical-human-identities.d.ts +48 -0
- package/dist/canonical-human-identities.js +28 -0
- package/dist/canonical-human-identities.js.map +1 -0
- package/dist/capability-integrations.d.ts +8 -6
- package/dist/{chunk-MWDVXQOL.js → chunk-5KTIEDX7.js} +5773 -4212
- package/dist/chunk-5KTIEDX7.js.map +1 -0
- package/dist/chunk-FPVAD4CO.js +117 -0
- package/dist/chunk-FPVAD4CO.js.map +1 -0
- package/dist/chunk-GYO7ED2Q.js +259 -0
- package/dist/chunk-GYO7ED2Q.js.map +1 -0
- package/dist/{chunk-F5FT7BEZ.js → chunk-HSOWSYOX.js} +2 -2
- package/dist/{chunk-YHZXQ7HP.js → chunk-VKLB2ZGI.js} +446 -19
- package/dist/chunk-VKLB2ZGI.js.map +1 -0
- package/dist/{chunk-NBE6CHRI.js → chunk-VTPRIXKG.js} +49 -9
- package/dist/chunk-VTPRIXKG.js.map +1 -0
- package/dist/{chunk-ISI2TIUG.js → chunk-Z7VYMNPZ.js} +76 -4
- package/dist/chunk-Z7VYMNPZ.js.map +1 -0
- package/dist/database.d.ts +5 -0
- package/dist/editable-artifact-durable-export.js +2 -2
- package/dist/editable-artifacts.js +3 -3
- package/dist/index.d.ts +467 -29
- package/dist/index.js +23247 -16232
- package/dist/index.js.map +1 -1
- package/dist/insights.d.ts +23 -7
- package/dist/integration-bindings.d.ts +24 -24
- package/dist/integration-facets.d.ts +99 -0
- package/dist/interaction-revisions.d.ts +11 -0
- package/dist/interaction-schema.d.ts +698 -34
- package/dist/persistence-errors.d.ts +8 -0
- package/dist/provision-roles.js +1 -1
- package/dist/runtime-posture.d.ts +8 -7
- package/dist/schema.d.ts +9464 -5412
- package/dist/schema.js +51 -9
- package/dist/session-control.d.ts +29 -3
- package/dist/session-tenancy.d.ts +44 -0
- package/dist/session-tenancy.js +16 -0
- package/dist/session-tenancy.js.map +1 -0
- package/dist/slack-task-policy-schema.d.ts +847 -0
- package/dist/slack-task-policy.d.ts +65 -0
- package/dist/task-notes-schema.d.ts +924 -0
- package/dist/task-notes.d.ts +85 -0
- package/dist/video-generation.d.ts +9 -0
- package/dist/video-generation.js +5 -3
- package/dist/xai-subscription.d.ts +326 -0
- package/drizzle/0212_browser_state_transfer_hardening.sql +560 -0
- package/drizzle/0213_browser_interaction_authority.sql +67 -0
- package/drizzle/0214_browser_download_saves.sql +34 -0
- package/drizzle/0215_browser_controller_host.sql +385 -0
- package/drizzle/0216_browser_auth_health_evidence.sql +137 -0
- package/drizzle/0217_external_browser_auth_operations.sql +22 -0
- package/drizzle/0218_organization_tenancy_foundation.sql +299 -0
- package/drizzle/0219_organization_tenancy_managed_human_provisioning.sql +317 -0
- package/drizzle/0219_site_auth_maintenance_sessions.sql +234 -0
- package/drizzle/0220_memory_slack_append_only_cascade.sql +38 -0
- package/drizzle/0220_session_channels.sql +54 -0
- package/drizzle/0221_sessions_channel_index.sql +5 -0
- package/drizzle/0222_session_visibility_authority_epochs.sql +158 -0
- package/drizzle/0222_sessions_channel_fk.sql +89 -0
- package/drizzle/0223_pending_tool_event_output.sql +55 -0
- package/drizzle/0223_sessions_channel_fk_validate.sql +118 -0
- package/drizzle/0224_slack_post_outcome_reconciliation.sql +123 -0
- package/drizzle/0225_session_visibility_fork_activation.sql +1363 -0
- package/drizzle/0226_personal_codex_authority_foundation.sql +365 -0
- package/drizzle/0227_slack_native_actions.sql +145 -0
- package/drizzle/0228_interaction_controller_data_plane.sql +14 -0
- package/drizzle/0228_slack_task_policy.sql +400 -0
- package/drizzle/0229_slack_inbox_file_fact.sql +10 -0
- package/drizzle/0230_user_scoped_variable_sets_rigs.sql +84 -0
- package/drizzle/0231_integration_definition_identity_cutover.sql +271 -0
- package/drizzle/0232_integration_facet_authority_cutover.sql +610 -0
- package/drizzle/0233_skill_and_integration_authority_cutover.sql +1162 -0
- package/drizzle/0234_xai_subscription_authority.sql +1139 -0
- package/drizzle/0235_canonical_human_login_bindings.sql +920 -0
- package/drizzle/0236_browser_identity_lifecycle.sql +39 -0
- package/drizzle/0236_session_visibility_slack_policy.sql +72 -0
- package/drizzle/0237_interaction_transition_reaper.sql +263 -0
- package/drizzle/0238_goal_persistence_policy.sql +471 -0
- package/drizzle/0238_recover_unclaimed_session_turns.sql +307 -0
- package/drizzle/0238_supergrok_realtime_model.sql +29 -0
- package/drizzle/0239_supergrok_video_funding.sql +50 -0
- package/drizzle/0239_task_tree_notes.sql +990 -0
- package/package.json +13 -5
- package/src/browser-auth.ts +2600 -123
- package/src/browser-downloads.ts +517 -0
- package/src/browser-identities.ts +220 -3
- package/src/browser-sessions.ts +334 -45
- package/src/browser-state-artifacts.ts +402 -12
- package/src/canonical-human-identities.ts +317 -0
- package/src/capability-integrations.ts +121 -213
- package/src/database.ts +41 -1
- package/src/index.ts +4625 -411
- package/src/insights.ts +109 -28
- package/src/integration-bindings.ts +101 -101
- package/src/{integration-features.ts → integration-facets.ts} +187 -184
- package/src/interaction-revisions.ts +33 -3
- package/src/interaction-schema.ts +311 -8
- package/src/pack-components.ts +43 -43
- package/src/pack-installations.ts +0 -43
- package/src/persistence-errors.ts +60 -1
- package/src/plugin-packages.ts +9 -9
- package/src/provision-roles.ts +232 -0
- package/src/runtime-posture.ts +227 -14
- package/src/schema.ts +1188 -75
- package/src/session-control.ts +122 -37
- package/src/session-queue-commands.ts +78 -1
- package/src/session-tenancy.ts +188 -0
- package/src/session-tool-call-settlement.ts +9 -3
- package/src/slack-task-policy-schema.ts +130 -0
- package/src/slack-task-policy.ts +341 -0
- package/src/task-notes-schema.ts +135 -0
- package/src/task-notes.ts +178 -0
- package/src/video-generation.ts +90 -12
- package/src/workspace-artifacts.ts +1 -1
- package/src/xai-subscription.ts +1887 -0
- package/dist/chunk-ISI2TIUG.js.map +0 -1
- package/dist/chunk-MWDVXQOL.js.map +0 -1
- package/dist/chunk-NBE6CHRI.js.map +0 -1
- package/dist/chunk-YHZXQ7HP.js.map +0 -1
- package/dist/integration-features.d.ts +0 -99
- /package/dist/{chunk-F5FT7BEZ.js.map → chunk-HSOWSYOX.js.map} +0 -0
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
-- deployment-mode: maintenance
|
|
2
|
+
-- Complete the saved-browser lifecycle with optimistic metadata updates and
|
|
3
|
+
-- replay-safe mutation receipts. Immutable revisions remain untouched.
|
|
4
|
+
SET LOCAL lock_timeout = '5s';
|
|
5
|
+
SET LOCAL statement_timeout = '30s';
|
|
6
|
+
|
|
7
|
+
ALTER TABLE "browser_identities"
|
|
8
|
+
ADD COLUMN "version" bigint NOT NULL DEFAULT 1;
|
|
9
|
+
|
|
10
|
+
ALTER TABLE "browser_identities"
|
|
11
|
+
DROP CONSTRAINT "browser_identities_values_check";
|
|
12
|
+
|
|
13
|
+
ALTER TABLE "browser_identities"
|
|
14
|
+
ADD CONSTRAINT "browser_identities_values_check" CHECK (
|
|
15
|
+
octet_length("name") BETWEEN 1 AND 200
|
|
16
|
+
AND "name" = btrim("name")
|
|
17
|
+
AND octet_length("created_by_subject_id") BETWEEN 1 AND 1024
|
|
18
|
+
AND "version" > 0
|
|
19
|
+
AND "head_generation" >= 0
|
|
20
|
+
AND "revision_count" >= 0
|
|
21
|
+
AND (
|
|
22
|
+
("head_generation" = 0 AND "default_revision_id" IS NULL)
|
|
23
|
+
OR ("head_generation" > 0 AND "default_revision_id" IS NOT NULL)
|
|
24
|
+
)
|
|
25
|
+
);
|
|
26
|
+
|
|
27
|
+
ALTER TABLE "interaction_resource_operations"
|
|
28
|
+
DROP CONSTRAINT "interaction_resource_operations_resource_kind_check";
|
|
29
|
+
|
|
30
|
+
ALTER TABLE "interaction_resource_operations"
|
|
31
|
+
ADD CONSTRAINT "interaction_resource_operations_resource_kind_check"
|
|
32
|
+
CHECK ("resource_kind" IN (
|
|
33
|
+
'browser_identity',
|
|
34
|
+
'network_route',
|
|
35
|
+
'site_auth_connection',
|
|
36
|
+
'auth_run',
|
|
37
|
+
'intervention',
|
|
38
|
+
'browser_download'
|
|
39
|
+
));
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
-- deployment-mode: rolling
|
|
2
|
+
-- Forward-repair direct session references introduced after migration 0225.
|
|
3
|
+
|
|
4
|
+
SET LOCAL lock_timeout = '5s';
|
|
5
|
+
SET LOCAL statement_timeout = '10min';
|
|
6
|
+
|
|
7
|
+
DO $session_visibility_slack_task_repair$
|
|
8
|
+
DECLARE
|
|
9
|
+
data_schema text := current_schema();
|
|
10
|
+
target_table text;
|
|
11
|
+
policy_expression text;
|
|
12
|
+
BEGIN
|
|
13
|
+
IF pg_catalog.to_regprocedure(
|
|
14
|
+
pg_catalog.format('%I.session_private_actor_visible(uuid,uuid,uuid,text)', data_schema)
|
|
15
|
+
) IS NULL OR pg_catalog.to_regprocedure(
|
|
16
|
+
pg_catalog.format('%I.session_reference_visible(uuid,uuid,uuid)', data_schema)
|
|
17
|
+
) IS NULL THEN
|
|
18
|
+
RAISE EXCEPTION 'session visibility helper chain is missing'
|
|
19
|
+
USING ERRCODE = '42883';
|
|
20
|
+
END IF;
|
|
21
|
+
|
|
22
|
+
EXECUTE pg_catalog.format(
|
|
23
|
+
'REVOKE ALL ON FUNCTION %I.session_private_actor_visible(uuid,uuid,uuid,text) FROM PUBLIC',
|
|
24
|
+
data_schema
|
|
25
|
+
);
|
|
26
|
+
EXECUTE pg_catalog.format(
|
|
27
|
+
'REVOKE ALL ON FUNCTION %I.session_reference_visible(uuid,uuid,uuid) FROM PUBLIC',
|
|
28
|
+
data_schema
|
|
29
|
+
);
|
|
30
|
+
IF EXISTS (SELECT 1 FROM pg_catalog.pg_roles WHERE rolname = 'opengeni_app') THEN
|
|
31
|
+
EXECUTE pg_catalog.format(
|
|
32
|
+
'GRANT EXECUTE ON FUNCTION %I.session_private_actor_visible(uuid,uuid,uuid,text) TO opengeni_app',
|
|
33
|
+
data_schema
|
|
34
|
+
);
|
|
35
|
+
EXECUTE pg_catalog.format(
|
|
36
|
+
'GRANT EXECUTE ON FUNCTION %I.session_reference_visible(uuid,uuid,uuid) TO opengeni_app',
|
|
37
|
+
data_schema
|
|
38
|
+
);
|
|
39
|
+
END IF;
|
|
40
|
+
|
|
41
|
+
FOREACH target_table IN ARRAY ARRAY[
|
|
42
|
+
'slack_interaction_action_handles',
|
|
43
|
+
'slack_shared_task_origins',
|
|
44
|
+
'xai_capacity_waiters',
|
|
45
|
+
'xai_session_account_pins'
|
|
46
|
+
]
|
|
47
|
+
LOOP
|
|
48
|
+
IF pg_catalog.to_regclass(pg_catalog.format('%I.%I', data_schema, target_table)) IS NULL THEN
|
|
49
|
+
RAISE EXCEPTION 'session visibility repair table is missing: %', target_table
|
|
50
|
+
USING ERRCODE = '42P01';
|
|
51
|
+
END IF;
|
|
52
|
+
|
|
53
|
+
policy_expression := pg_catalog.format(
|
|
54
|
+
'%I.session_reference_visible(account_id, workspace_id, session_id)',
|
|
55
|
+
data_schema
|
|
56
|
+
);
|
|
57
|
+
EXECUTE pg_catalog.format(
|
|
58
|
+
'DROP POLICY IF EXISTS session_visibility_isolation ON %I.%I',
|
|
59
|
+
data_schema,
|
|
60
|
+
target_table
|
|
61
|
+
);
|
|
62
|
+
EXECUTE pg_catalog.format(
|
|
63
|
+
'CREATE POLICY session_visibility_isolation ON %I.%I AS RESTRICTIVE '
|
|
64
|
+
|| 'FOR ALL USING (%s) WITH CHECK (%s)',
|
|
65
|
+
data_schema,
|
|
66
|
+
target_table,
|
|
67
|
+
policy_expression,
|
|
68
|
+
policy_expression
|
|
69
|
+
);
|
|
70
|
+
END LOOP;
|
|
71
|
+
END
|
|
72
|
+
$session_visibility_slack_task_repair$;
|
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
-- deployment-mode: maintenance
|
|
2
|
+
-- Settle controller transitions whose API owner disappeared after dispatch.
|
|
3
|
+
-- Active Browser/Computer sessions are deliberately excluded: their durable
|
|
4
|
+
-- placement must survive a hidden UI, a closed laptop, and long human login.
|
|
5
|
+
SET LOCAL lock_timeout = '5s';
|
|
6
|
+
SET LOCAL statement_timeout = '30s';
|
|
7
|
+
|
|
8
|
+
DO $transition_reaper$
|
|
9
|
+
DECLARE data_schema text := current_schema();
|
|
10
|
+
BEGIN
|
|
11
|
+
EXECUTE format($create$
|
|
12
|
+
CREATE OR REPLACE FUNCTION opengeni_private.reap_stale_interaction_transitions(
|
|
13
|
+
p_interaction_holder_ttl_ms bigint
|
|
14
|
+
)
|
|
15
|
+
RETURNS integer
|
|
16
|
+
LANGUAGE plpgsql
|
|
17
|
+
SECURITY DEFINER
|
|
18
|
+
SET search_path = pg_catalog
|
|
19
|
+
AS $function$
|
|
20
|
+
DECLARE
|
|
21
|
+
stale_operation_ids uuid[] := ARRAY[]::uuid[];
|
|
22
|
+
stale_browser_ids uuid[] := ARRAY[]::uuid[];
|
|
23
|
+
stale_computer_ids uuid[] := ARRAY[]::uuid[];
|
|
24
|
+
changed_workspace_ids uuid[] := ARRAY[]::uuid[];
|
|
25
|
+
orphan_workspace_ids uuid[] := ARRAY[]::uuid[];
|
|
26
|
+
affected_lease_ids uuid[] := ARRAY[]::uuid[];
|
|
27
|
+
settled_count integer := 0;
|
|
28
|
+
BEGIN
|
|
29
|
+
IF p_interaction_holder_ttl_ms <= 0 THEN
|
|
30
|
+
RETURN 0;
|
|
31
|
+
END IF;
|
|
32
|
+
|
|
33
|
+
-- The exact lifecycle operation is the request-owner heartbeat. Long
|
|
34
|
+
-- controller calls pulse updated_at; a stale dispatched operation means
|
|
35
|
+
-- the caller vanished. Prepared operations cannot have a physical side
|
|
36
|
+
-- effect yet and remain replayable, so they are intentionally excluded.
|
|
37
|
+
SELECT coalesce(pg_catalog.array_agg(candidate.operation_id), ARRAY[]::uuid[])
|
|
38
|
+
INTO stale_operation_ids
|
|
39
|
+
FROM (
|
|
40
|
+
SELECT operation.operation_id
|
|
41
|
+
FROM %1$I.interaction_operations operation
|
|
42
|
+
WHERE operation.state = 'dispatched'
|
|
43
|
+
AND operation.updated_at
|
|
44
|
+
< pg_catalog.now()
|
|
45
|
+
- pg_catalog.make_interval(
|
|
46
|
+
secs => p_interaction_holder_ttl_ms / 1000.0
|
|
47
|
+
)
|
|
48
|
+
AND (
|
|
49
|
+
EXISTS (
|
|
50
|
+
SELECT 1
|
|
51
|
+
FROM %1$I.browser_sessions browser
|
|
52
|
+
WHERE operation.resource_kind = 'browser_session'
|
|
53
|
+
AND operation.account_id = browser.account_id
|
|
54
|
+
AND operation.workspace_id = browser.workspace_id
|
|
55
|
+
AND operation.resource_id = browser.id
|
|
56
|
+
AND browser.lifecycle IN (
|
|
57
|
+
'starting', 'suspending', 'restoring', 'ending'
|
|
58
|
+
)
|
|
59
|
+
)
|
|
60
|
+
OR EXISTS (
|
|
61
|
+
SELECT 1
|
|
62
|
+
FROM %1$I.computer_sessions computer
|
|
63
|
+
WHERE operation.resource_kind = 'computer_session'
|
|
64
|
+
AND operation.account_id = computer.account_id
|
|
65
|
+
AND operation.workspace_id = computer.workspace_id
|
|
66
|
+
AND operation.resource_id = computer.id
|
|
67
|
+
AND computer.lifecycle IN ('starting', 'ending')
|
|
68
|
+
)
|
|
69
|
+
)
|
|
70
|
+
ORDER BY operation.updated_at, operation.operation_id
|
|
71
|
+
LIMIT 500
|
|
72
|
+
FOR UPDATE OF operation SKIP LOCKED
|
|
73
|
+
) candidate;
|
|
74
|
+
|
|
75
|
+
SELECT coalesce(
|
|
76
|
+
pg_catalog.array_agg(operation.resource_id)
|
|
77
|
+
FILTER (WHERE operation.resource_kind = 'browser_session'),
|
|
78
|
+
ARRAY[]::uuid[]
|
|
79
|
+
),
|
|
80
|
+
coalesce(
|
|
81
|
+
pg_catalog.array_agg(operation.resource_id)
|
|
82
|
+
FILTER (WHERE operation.resource_kind = 'computer_session'),
|
|
83
|
+
ARRAY[]::uuid[]
|
|
84
|
+
),
|
|
85
|
+
coalesce(
|
|
86
|
+
pg_catalog.array_agg(DISTINCT operation.workspace_id),
|
|
87
|
+
ARRAY[]::uuid[]
|
|
88
|
+
)
|
|
89
|
+
INTO stale_browser_ids, stale_computer_ids, changed_workspace_ids
|
|
90
|
+
FROM %1$I.interaction_operations operation
|
|
91
|
+
WHERE operation.operation_id = ANY(stale_operation_ids);
|
|
92
|
+
|
|
93
|
+
-- Lock every affected lease before its holder, matching lease acquire,
|
|
94
|
+
-- release and the ordinary global reaper. Connected-machine transitions
|
|
95
|
+
-- have no lease and still settle through the same operation contract.
|
|
96
|
+
SELECT coalesce(pg_catalog.array_agg(DISTINCT holder.lease_id), ARRAY[]::uuid[])
|
|
97
|
+
INTO affected_lease_ids
|
|
98
|
+
FROM %1$I.sandbox_lease_holders holder
|
|
99
|
+
WHERE holder.kind = 'interaction'
|
|
100
|
+
AND (
|
|
101
|
+
holder.holder_id IN (
|
|
102
|
+
SELECT 'browser-session:' || id::text
|
|
103
|
+
FROM pg_catalog.unnest(stale_browser_ids) ids(id)
|
|
104
|
+
)
|
|
105
|
+
OR holder.holder_id IN (
|
|
106
|
+
SELECT 'computer-session:' || id::text
|
|
107
|
+
FROM pg_catalog.unnest(stale_computer_ids) ids(id)
|
|
108
|
+
)
|
|
109
|
+
);
|
|
110
|
+
|
|
111
|
+
PERFORM lease.id
|
|
112
|
+
FROM %1$I.sandbox_leases lease
|
|
113
|
+
WHERE lease.id = ANY(affected_lease_ids)
|
|
114
|
+
ORDER BY lease.id
|
|
115
|
+
FOR UPDATE OF lease;
|
|
116
|
+
|
|
117
|
+
PERFORM holder.id
|
|
118
|
+
FROM %1$I.sandbox_lease_holders holder
|
|
119
|
+
WHERE holder.lease_id = ANY(affected_lease_ids)
|
|
120
|
+
AND holder.kind = 'interaction'
|
|
121
|
+
AND (
|
|
122
|
+
holder.holder_id IN (
|
|
123
|
+
SELECT 'browser-session:' || id::text
|
|
124
|
+
FROM pg_catalog.unnest(stale_browser_ids) ids(id)
|
|
125
|
+
)
|
|
126
|
+
OR holder.holder_id IN (
|
|
127
|
+
SELECT 'computer-session:' || id::text
|
|
128
|
+
FROM pg_catalog.unnest(stale_computer_ids) ids(id)
|
|
129
|
+
)
|
|
130
|
+
)
|
|
131
|
+
ORDER BY holder.id
|
|
132
|
+
FOR UPDATE OF holder;
|
|
133
|
+
|
|
134
|
+
UPDATE %1$I.interaction_operations operation
|
|
135
|
+
SET state = 'outcome_unknown',
|
|
136
|
+
error_code = 'controller_transition_expired',
|
|
137
|
+
error_message = 'Interaction controller transition heartbeat expired',
|
|
138
|
+
error_retryable = false,
|
|
139
|
+
error_details = pg_catalog.jsonb_build_object(
|
|
140
|
+
'reason', 'transition_heartbeat_expired'
|
|
141
|
+
),
|
|
142
|
+
settled_at = pg_catalog.now(),
|
|
143
|
+
updated_at = pg_catalog.now()
|
|
144
|
+
WHERE operation.operation_id = ANY(stale_operation_ids)
|
|
145
|
+
AND operation.state = 'dispatched';
|
|
146
|
+
GET DIAGNOSTICS settled_count = ROW_COUNT;
|
|
147
|
+
|
|
148
|
+
-- Outcome is unknown: retain the exact controller binding so a subsequent
|
|
149
|
+
-- end/cleanup can target the same generation. The lease holder is released
|
|
150
|
+
-- below; provider drain remains the final physical cleanup fence.
|
|
151
|
+
UPDATE %1$I.browser_sessions browser
|
|
152
|
+
SET lifecycle = 'lost',
|
|
153
|
+
failure_code = 'controller_transition_expired',
|
|
154
|
+
updated_at = pg_catalog.now()
|
|
155
|
+
WHERE browser.id = ANY(stale_browser_ids)
|
|
156
|
+
AND browser.lifecycle IN (
|
|
157
|
+
'starting', 'suspending', 'restoring', 'ending'
|
|
158
|
+
);
|
|
159
|
+
|
|
160
|
+
UPDATE %1$I.computer_sessions computer
|
|
161
|
+
SET lifecycle = 'lost',
|
|
162
|
+
failure_code = 'controller_transition_expired',
|
|
163
|
+
updated_at = pg_catalog.now()
|
|
164
|
+
WHERE computer.id = ANY(stale_computer_ids)
|
|
165
|
+
AND computer.lifecycle IN ('starting', 'ending');
|
|
166
|
+
|
|
167
|
+
-- Terminal/mismatched interaction holders are lifecycle orphans. Include
|
|
168
|
+
-- the transitions settled above plus missed best-effort releases after a
|
|
169
|
+
-- successful suspend/end/failure. Active controllers remain immortal.
|
|
170
|
+
SELECT coalesce(pg_catalog.array_agg(DISTINCT holder.lease_id), ARRAY[]::uuid[]),
|
|
171
|
+
coalesce(pg_catalog.array_agg(DISTINCT holder.workspace_id), ARRAY[]::uuid[])
|
|
172
|
+
INTO affected_lease_ids, orphan_workspace_ids
|
|
173
|
+
FROM %1$I.sandbox_lease_holders holder
|
|
174
|
+
JOIN %1$I.sandbox_leases lease ON lease.id = holder.lease_id
|
|
175
|
+
WHERE holder.kind = 'interaction'
|
|
176
|
+
AND NOT (
|
|
177
|
+
EXISTS (
|
|
178
|
+
SELECT 1
|
|
179
|
+
FROM %1$I.browser_sessions browser
|
|
180
|
+
WHERE holder.holder_id = ('browser-session:' || browser.id::text)
|
|
181
|
+
AND holder.account_id = browser.account_id
|
|
182
|
+
AND holder.workspace_id = browser.workspace_id
|
|
183
|
+
AND browser.controller_host_sandbox_group_id = lease.sandbox_group_id
|
|
184
|
+
AND browser.lifecycle IN (
|
|
185
|
+
'starting', 'active', 'suspending', 'restoring', 'ending'
|
|
186
|
+
)
|
|
187
|
+
)
|
|
188
|
+
OR EXISTS (
|
|
189
|
+
SELECT 1
|
|
190
|
+
FROM %1$I.computer_sessions computer
|
|
191
|
+
WHERE holder.holder_id = ('computer-session:' || computer.id::text)
|
|
192
|
+
AND holder.account_id = computer.account_id
|
|
193
|
+
AND holder.workspace_id = computer.workspace_id
|
|
194
|
+
AND computer.sandbox_group_id = lease.sandbox_group_id
|
|
195
|
+
AND computer.lifecycle IN (
|
|
196
|
+
'starting', 'active', 'suspending', 'restoring', 'ending'
|
|
197
|
+
)
|
|
198
|
+
)
|
|
199
|
+
);
|
|
200
|
+
|
|
201
|
+
PERFORM lease.id
|
|
202
|
+
FROM %1$I.sandbox_leases lease
|
|
203
|
+
WHERE lease.id = ANY(affected_lease_ids)
|
|
204
|
+
ORDER BY lease.id
|
|
205
|
+
FOR UPDATE OF lease;
|
|
206
|
+
|
|
207
|
+
DELETE FROM %1$I.sandbox_lease_holders holder
|
|
208
|
+
USING %1$I.sandbox_leases lease
|
|
209
|
+
WHERE holder.lease_id = lease.id
|
|
210
|
+
AND holder.lease_id = ANY(affected_lease_ids)
|
|
211
|
+
AND holder.kind = 'interaction'
|
|
212
|
+
AND NOT (
|
|
213
|
+
EXISTS (
|
|
214
|
+
SELECT 1
|
|
215
|
+
FROM %1$I.browser_sessions browser
|
|
216
|
+
WHERE holder.holder_id = ('browser-session:' || browser.id::text)
|
|
217
|
+
AND holder.account_id = browser.account_id
|
|
218
|
+
AND holder.workspace_id = browser.workspace_id
|
|
219
|
+
AND browser.controller_host_sandbox_group_id = lease.sandbox_group_id
|
|
220
|
+
AND browser.lifecycle IN (
|
|
221
|
+
'starting', 'active', 'suspending', 'restoring', 'ending'
|
|
222
|
+
)
|
|
223
|
+
)
|
|
224
|
+
OR EXISTS (
|
|
225
|
+
SELECT 1
|
|
226
|
+
FROM %1$I.computer_sessions computer
|
|
227
|
+
WHERE holder.holder_id = ('computer-session:' || computer.id::text)
|
|
228
|
+
AND holder.account_id = computer.account_id
|
|
229
|
+
AND holder.workspace_id = computer.workspace_id
|
|
230
|
+
AND computer.sandbox_group_id = lease.sandbox_group_id
|
|
231
|
+
AND computer.lifecycle IN (
|
|
232
|
+
'starting', 'active', 'suspending', 'restoring', 'ending'
|
|
233
|
+
)
|
|
234
|
+
)
|
|
235
|
+
);
|
|
236
|
+
|
|
237
|
+
UPDATE %1$I.workspace_interaction_revisions revision
|
|
238
|
+
SET revision = revision.revision + 1,
|
|
239
|
+
updated_at = pg_catalog.now()
|
|
240
|
+
WHERE revision.workspace_id = ANY(changed_workspace_ids || orphan_workspace_ids);
|
|
241
|
+
|
|
242
|
+
RETURN settled_count;
|
|
243
|
+
END;
|
|
244
|
+
$function$;
|
|
245
|
+
$create$, data_schema);
|
|
246
|
+
END
|
|
247
|
+
$transition_reaper$;
|
|
248
|
+
|
|
249
|
+
REVOKE ALL ON FUNCTION opengeni_private.reap_stale_interaction_transitions(bigint)
|
|
250
|
+
FROM PUBLIC;
|
|
251
|
+
|
|
252
|
+
DO $reaper_grant$
|
|
253
|
+
BEGIN
|
|
254
|
+
IF EXISTS (SELECT 1 FROM pg_roles WHERE rolname = 'opengeni_app') THEN
|
|
255
|
+
GRANT EXECUTE ON FUNCTION
|
|
256
|
+
opengeni_private.reap_stale_interaction_transitions(bigint)
|
|
257
|
+
TO opengeni_app;
|
|
258
|
+
END IF;
|
|
259
|
+
END
|
|
260
|
+
$reaper_grant$;
|
|
261
|
+
|
|
262
|
+
RESET statement_timeout;
|
|
263
|
+
RESET lock_timeout;
|