toga-ai 1.0.544 → 1.0.545
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/knowledge/2.0/apps/worker2/INDEX.md +1 -0
- package/knowledge/2.0/apps/worker2/features/all-client-email-queue-monitor.md +1 -0
- package/knowledge/2.0/apps/worker2/features/netsuite-integrations-monitor.md +139 -0
- package/knowledge/2.0/apps/worker2/features/oneuptime-worker2-monitoring.md +23 -0
- package/knowledge/INDEX.md +1 -1
- package/package.json +1 -1
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
| [Etilize Catalog Item Import & Refresh](features/etilize-catalog-item-import.md) | Client-generic catalog onboarding from an S3 CSV plus an Etilize re-pull. | worker2/Worker/Etilize/Items.php |
|
|
24
24
|
| [Etilize Item Translation Import](features/etilize-item-translation-import.md) | The abstract worker class `_Worker_Etilize_ItemTranslations` imports **non-English** item text from Etilize into the client's `ItemTranslations` table. | worker2/Worker/Etilize/ItemTranslations.php |
|
|
25
25
|
| [Monitoring Framework (Orchestrator + Child Monitors)](features/monitoring-framework.md) | A unified, DB-driven monitoring framework for business-critical data flows (Compass POs, Prudential asset imports, AIG closed claims, …). | worker2/Worker/Monitor.php, worker2/Worker/Monitors/, worker2/Worker/Monitors/RateEntitlement.php, worker2/Worker/Notification/Email.php, worker2/Worker/Rate.php, dbchanges2/Core/2026-05-21 - Monitors.sql, dbchanges2/Core/2026-06-29a - Rate Entitlement Contract Monitor.sql |
|
|
26
|
+
| [NetSuite Integrations Monitor (Monitor/Operations/NetsuiteIntegrations)](features/netsuite-integrations-monitor.md) | `_Worker_Monitor_Operations::NetsuiteIntegrations()` is a cross-client health check that detects **stuck NetSuite ↔ 2.0 integrations**. | worker2/Worker/Monitor/Operations.php, dbchanges2/Core/2026-08-10a - Netsuite Integrations Monitor.sql, _underscore/Database.php, _underscore/Query.php |
|
|
26
27
|
| [NetSuite ↔ ClickUp / TOGA Opportunity Sync (API Message Queue + worker2 webhook)](features/netsuite-opportunity-sync.md) | Outbound sync from NetSuite to TOGA for the record types the Forecast2 importer pulls (opportunities first; sales/items/etc. | worker2/Worker/Netsuite.php, worker2/Worker/Netsuite/Opportunity.php, worker2/Worker/Clickup.php, worker2/Worker/Clickup/Opportunity.php, worker2/Controller/Index.php, _underscore/Worker.php, test/@dave/NetSuite/api-message-queue/lib_amq_queue.js, test/@dave/NetSuite/api-message-queue/ue_api_msg_queue_enqueue.js, test/@dave/NetSuite/api-message-queue/ue_amq_drain.js, test/@dave/NetSuite/api-message-queue/ss_amq_drain.js, test/@dave/NetSuite/api-message-queue/DEPLOY_RUNBOOK.md, test/@dave/clickup/backfill_opportunity_numbers.php, test/@dave/clickup/probe_opportunity_fields.php, test/@dave/probe_clickup_desc_match.php, test/@dave/test_model_load_behavior.php, dbchanges2/Forecast/2026-06-25a - Add unique index on Opportunities netsuiteOpportunityInternalId.sql, _underscore/Model/Forecast/Opportunity.php, test/@dave/approach/TRUE-80044.md, worker/crons/toga2/forecast2/common_import_sales_from_netsuite.php |
|
|
27
28
|
| [NetSuite → Forecast Open-Orders Sync (salesOrder webhook → OpenOrderItems)](features/netsuite-salesorder-open-orders-sync.md) | Webhook-driven, single-record port of the legacy open-orders importer (TRUE-79142). | worker2/Worker/Netsuite/SalesOrder.php, worker2/Worker/Netsuite.php, worker2/Component/Forecast/Db/Db.php, worker2/Worker/Netsuite/Location.php, test/@dave/Junk Drawer/NetSuite/api-message-queue/ue_api_msg_queue_enqueue.js, test/@dave/Junk Drawer/NetSuite/api-message-queue/ue_amq_invoice_resync_salesorder.js, test/@dave/probe_salesorder_rest_shape.php, test/@dave/probe_open_order_lines.php, test/@dave/check_so_status.php, test/@dave/check_so_history.php, test/@dave/probe_so_rest_lines.php, test/@dave/probe_missing_oo_timing.php, test/@dave/probe_missing_oo_createdby.php, test/@dave/probe_drift_so_dates.php, test/@dave/probe_open_order_gating.php, worker/crons/toga2/forecast2/import_open_orders.php, worker/crons/toga2/forecast2/common_import_sales_from_netsuite.php |
|
|
28
29
|
| [NetSuite Supporting-Record Webhook Importer (the reusable recipe)](features/netsuite-supporting-record-webhook-importer.md) | A single **repeatable recipe** for porting a legacy daily-pull NetSuite *supporting-record* importer (the lookup/dimension tables behind Forecast2 — Employees, | worker2/Worker/Netsuite/Employee.php, worker2/Worker/Netsuite/Account.php, worker2/Worker/Netsuite/Classification.php, worker2/Worker/Netsuite/Customer.php, worker2/Worker/Netsuite/Item.php, worker2/Worker/Netsuite.php, _underscore/Model/Forecast/Employee.php, _underscore/Model/Forecast/Account.php, _underscore/Model/Forecast/Classification.php, _underscore/Component/Forecast/Db/Db.php, test/@dave/test_employee_lifecycle.php, test/@dave/test_account_lifecycle.php, test/@dave/test_classification_lifecycle.php, test/@dave/NetSuite/api-message-queue/ue_api_msg_queue_enqueue.js, worker/crons/toga2/forecast2/import_supporting_records.php |
|
|
@@ -15,6 +15,7 @@ files:
|
|
|
15
15
|
- dbchanges2/Logs_Client/2026-05-21 - Email.sql
|
|
16
16
|
related:
|
|
17
17
|
- ./oneuptime-worker2-monitoring.md
|
|
18
|
+
- ./netsuite-integrations-monitor.md
|
|
18
19
|
- ./monitoring-framework.md
|
|
19
20
|
- ../../_underscore/features/email-send-pipeline.md
|
|
20
21
|
- ../../_underscore/features/per-client-database-connections.md
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
---
|
|
2
|
+
title: NetSuite Integrations Monitor (Monitor/Operations/NetsuiteIntegrations)
|
|
3
|
+
framework: "2.0"
|
|
4
|
+
repo: worker2
|
|
5
|
+
project: Worker
|
|
6
|
+
client: shared
|
|
7
|
+
type: feature
|
|
8
|
+
status: active
|
|
9
|
+
updated: 2026-08-10
|
|
10
|
+
owners: ["jcardinal"]
|
|
11
|
+
files:
|
|
12
|
+
- worker2/Worker/Monitor/Operations.php
|
|
13
|
+
- dbchanges2/Core/2026-08-10a - Netsuite Integrations Monitor.sql
|
|
14
|
+
- _underscore/Database.php
|
|
15
|
+
- _underscore/Query.php
|
|
16
|
+
related:
|
|
17
|
+
- ./all-client-email-queue-monitor.md
|
|
18
|
+
- ./oneuptime-worker2-monitoring.md
|
|
19
|
+
- ./monitoring-framework.md
|
|
20
|
+
- ../../_underscore/features/per-client-database-connections.md
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
## Summary
|
|
24
|
+
|
|
25
|
+
`_Worker_Monitor_Operations::NetsuiteIntegrations()` is a cross-client health check that
|
|
26
|
+
detects **stuck NetSuite ↔ 2.0 integrations**. It sweeps **every** client's business
|
|
27
|
+
database (`Client_<X>`), looks in the `Parameters` table for rows where
|
|
28
|
+
`` `key` `` LIKE `NETSUITE_EXECUTION_MODE_%` and `` `value` `` LIKE `1-RUNNING`, and pushes
|
|
29
|
+
one aggregate payload to a single OneUptime Incoming Request monitor with the **offending
|
|
30
|
+
integrations named** in the body. A row parked at the `1-RUNNING` sentinel means an
|
|
31
|
+
integration hung mid-run.
|
|
32
|
+
|
|
33
|
+
This is the second all-client monitor in `_Worker_Monitor_Operations`, modeled exactly on
|
|
34
|
+
its sibling [EmailQueue](./all-client-email-queue-monitor.md) — a "dumb reporter, smart
|
|
35
|
+
monitor": the worker only reports measured values and OneUptime holds the alarm
|
|
36
|
+
thresholds. It is **shared internal operational infrastructure**, not a client feature.
|
|
37
|
+
|
|
38
|
+
## Key files / entry points
|
|
39
|
+
|
|
40
|
+
- `worker2/Worker/Monitor/Operations.php` — `abstract class _Worker_Monitor_Operations`.
|
|
41
|
+
- `public static function NetsuiteIntegrations(): string` — the action, route
|
|
42
|
+
`Monitor/Operations/NetsuiteIntegrations`.
|
|
43
|
+
- `private static function resolveClientDatabases(): array` — one `DB_CORE` query
|
|
44
|
+
returning every client + its **business** database name (`Client_<X>`) + this
|
|
45
|
+
environment's hosts. Mirrors `resolveClientLogDatabases()` but joins `Core.Clients` on
|
|
46
|
+
`clientDatabaseId` (not `logDatabaseId`).
|
|
47
|
+
- `dbchanges2/Core/2026-08-10a - Netsuite Integrations Monitor.sql` — the `Core.CronJobs`
|
|
48
|
+
seed row (see below).
|
|
49
|
+
- Dispatched by action string, not PHP import — the autoloader + `_Worker::runTask()`
|
|
50
|
+
reach the class via the cron action path.
|
|
51
|
+
|
|
52
|
+
## How it works
|
|
53
|
+
|
|
54
|
+
1. **Resolve every client's business database.** `resolveClientDatabases()` joins
|
|
55
|
+
`Clients` → `Databases` (via `Clients.clientDatabaseId`) → `DatabaseHosts` →
|
|
56
|
+
`Environments`/`Regions`, all **LEFT OUTER JOINs** so a misconfigured client is
|
|
57
|
+
reported, not silently dropped (`unresolvedClients`). Closest region first; later rows
|
|
58
|
+
for the same client are skipped.
|
|
59
|
+
2. **Register each client's business DB under its REAL database name, no alias**, guarded
|
|
60
|
+
by `if (!isset(_Database::$_registers[$dbName]))`, then query via `_Query`. A per-client
|
|
61
|
+
loop cannot reuse a shared alias — every iteration would clobber it.
|
|
62
|
+
3. **Sweep `Parameters` per client:**
|
|
63
|
+
`` SELECT `key`, `value` FROM Parameters WHERE `key` LIKE 'NETSUITE_EXECUTION_MODE_%' AND `value` LIKE '1-RUNNING' ``.
|
|
64
|
+
The integration **type** is the key with the `NETSUITE_EXECUTION_MODE_` prefix stripped
|
|
65
|
+
via `substr()` (e.g. `NETSUITE_EXECUTION_MODE_SALES_ORDERS` → `SALES_ORDERS`).
|
|
66
|
+
4. **Bucket each client** into `checked`, `skipped` (no `Parameters` table —
|
|
67
|
+
`isMissingTableError()`), or `unreachable` (any other query/connection failure). A
|
|
68
|
+
per-client `try/catch (Throwable)` keeps one bad client from failing the sweep.
|
|
69
|
+
5. **Decide the tokens and push once** to OneUptime.
|
|
70
|
+
|
|
71
|
+
### Payload contract — `alarm` and `probe` are SEPARATE tokens
|
|
72
|
+
|
|
73
|
+
Follows the [OneUptime push-metric pattern](./oneuptime-worker2-monitoring.md): OneUptime
|
|
74
|
+
can only string-match a body, so the worker decides and emits tokens.
|
|
75
|
+
|
|
76
|
+
| Field | Meaning |
|
|
77
|
+
|---|---|
|
|
78
|
+
| `status` | `reporting`, or `error` (reserved for the Core lookup itself failing → `error:client_lookup_failed`) |
|
|
79
|
+
| `alarm` | `DEGRADED` when any stuck integration is found, else `OK` |
|
|
80
|
+
| `probe` | `DEGRADED` when any client DB is unreachable, else `OK` |
|
|
81
|
+
| `stuckCount` | number of stuck integrations found |
|
|
82
|
+
| `offendingIntegrations` | comma-joined `"ClientName: TYPE"` |
|
|
83
|
+
| `clientsChecked`, `clientsSkipped` | coverage counters |
|
|
84
|
+
| `unreachableClients`, `unresolvedClients` | named coverage gaps |
|
|
85
|
+
| `checkedAtUtc` | `gmdate('c')` |
|
|
86
|
+
|
|
87
|
+
## Cron seed (dbchanges2)
|
|
88
|
+
|
|
89
|
+
`dbchanges2/Core/2026-08-10a - Netsuite Integrations Monitor.sql` — INSERT into
|
|
90
|
+
`Core.CronJobs`: action `Monitor/Operations/NetsuiteIntegrations`, schedule
|
|
91
|
+
`*/10 * * * *` (every 10 min), `maxExecutionTime` 120, `isActive` 1, `parameters` NULL,
|
|
92
|
+
fixed random uuid. Targets **only** `Core` (no cross-cluster refs), INSERT-only and
|
|
93
|
+
unguarded per dbchanges2 conventions. Modeled on
|
|
94
|
+
`Core/2026-07-29a - AIG Entitlement API Failure Monitor.sql`.
|
|
95
|
+
|
|
96
|
+
**Shipped `isActive=1` while the OneUptime URL is still a placeholder** (developer's
|
|
97
|
+
choice): the sweep runs but the push fails soft (`error_log`) until the real URL is pasted
|
|
98
|
+
into the worker method.
|
|
99
|
+
|
|
100
|
+
## Gotchas / known issues
|
|
101
|
+
|
|
102
|
+
- **`` `key` `` and `` `value` `` are MySQL reserved words** — backtick-quote them in the
|
|
103
|
+
`Parameters` query.
|
|
104
|
+
- **Single source of truth for the key prefix.** `$KEY_PREFIX` builds both the `LIKE`
|
|
105
|
+
pattern (via `_Database::escape`) and the `substr()` that derives the integration type;
|
|
106
|
+
never hardcode the prefix twice.
|
|
107
|
+
- **Never-throw / 200-on-all-paths.** The method always returns a summary string. The
|
|
108
|
+
OneUptime push is `setLogging(false)` + `setThrowExceptionsOnFailure(false)` **and**
|
|
109
|
+
wrapped in its own `try/catch`, so a failed ping never fails the worker job.
|
|
110
|
+
- **OneUptime push URL is a credential** — it lives only as an in-file value in the worker
|
|
111
|
+
method, never committed to dbchanges2 and never recorded in a doc. It is currently a
|
|
112
|
+
placeholder.
|
|
113
|
+
- **Business DB, not logs DB.** Join `Clients.clientDatabaseId` for `Client_<X>`; the
|
|
114
|
+
sibling EmailQueue monitor joins `logDatabaseId` for `Logs_<X>`. See
|
|
115
|
+
[per-client database connections](../../_underscore/features/per-client-database-connections.md).
|
|
116
|
+
- The all-client resolution gotchas from
|
|
117
|
+
[EmailQueue](./all-client-email-queue-monitor.md) apply verbatim: LEFT OUTER JOIN every
|
|
118
|
+
level, null host columns unless the environment join matched, detect missing table by
|
|
119
|
+
MySQL error **number** 1146 (not message text), and remember a passing dev run (single
|
|
120
|
+
all-in-one endpoint) does not prove cross-cluster correctness.
|
|
121
|
+
|
|
122
|
+
## Change history
|
|
123
|
+
|
|
124
|
+
- 2026-08-10 — Built `NetsuiteIntegrations()` + `resolveClientDatabases()` on
|
|
125
|
+
`_Worker_Monitor_Operations` (all-client `Parameters` sweep for
|
|
126
|
+
`NETSUITE_EXECUTION_MODE_%` = `1-RUNNING`), plus the `Core.CronJobs` seed
|
|
127
|
+
(`*/10 * * * *`, `isActive=1`) and an OneUptime Incoming Request monitor import. OneUptime
|
|
128
|
+
URL still a placeholder; sweep runs and pushes fail-soft until pasted. (jcardinal)
|
|
129
|
+
|
|
130
|
+
## Related docs
|
|
131
|
+
|
|
132
|
+
- [All-Client Email Queue Monitor](./all-client-email-queue-monitor.md) — the sibling
|
|
133
|
+
all-client monitor this one is modeled on.
|
|
134
|
+
- [OneUptime push-metric monitors for 2.0 workers](./oneuptime-worker2-monitoring.md) — the
|
|
135
|
+
push/token pattern and OneUptime criteria (incl. `{{requestBody.*}}` incident templating).
|
|
136
|
+
- [Per-Client Database Connections](../../_underscore/features/per-client-database-connections.md)
|
|
137
|
+
— business/log database name resolution.
|
|
138
|
+
</content>
|
|
139
|
+
</invoke>
|
|
@@ -111,6 +111,25 @@ log dive. `status: "error"` stays reserved for the checker being **fully** blind
|
|
|
111
111
|
resolution query failed). Worked example:
|
|
112
112
|
[All-Client Email Queue Monitor](./all-client-email-queue-monitor.md).
|
|
113
113
|
|
|
114
|
+
### Incident / alert title & description templating (`{{requestBody.*}}`)
|
|
115
|
+
|
|
116
|
+
OneUptime incident and alert **titles and descriptions support `{{variable}}` templating**
|
|
117
|
+
(verified against OneUptime docs 2026-08-10). For an **Incoming Request** monitor, the
|
|
118
|
+
POSTed JSON body is addressed via the `requestBody` prefix — e.g.
|
|
119
|
+
`{{requestBody.offendingIntegrations}}`, `{{requestBody.stuckCount}}`,
|
|
120
|
+
`{{requestBody.checkedAtUtc}}`, `{{requestBody.message}}`. Other available vars:
|
|
121
|
+
`{{requestHeaders}}`, `{{requestMethod}}`, `{{incomingRequestReceivedAt}}`.
|
|
122
|
+
|
|
123
|
+
- **Missing paths resolve to empty string**, so one template covers both a normal degraded
|
|
124
|
+
payload and an edge case like `error:client_lookup_failed` without a second template.
|
|
125
|
+
- Body-content criteria use `checkOn: "Request Body"` / `filterType: "Contains"`; the
|
|
126
|
+
heartbeat criterion uses `"Not Recieved In Minutes"` (note OneUptime's misspelling).
|
|
127
|
+
- A degraded criterion can OR several tokens, e.g. Contains `"alarm":"DEGRADED"` **OR**
|
|
128
|
+
`"error":"client_lookup_failed"`.
|
|
129
|
+
- Reuse the project's existing status/severity ObjectIDs when authoring the import JSON.
|
|
130
|
+
- Docs: https://oneuptime.com/docs/monitor/incident-alert-templating and
|
|
131
|
+
https://oneuptime.com/docs/en/monitor/incoming-request-monitor
|
|
132
|
+
|
|
114
133
|
### Heartbeat / cron cadence timing
|
|
115
134
|
|
|
116
135
|
The 10-min-Degraded / 15-min-Offline heartbeat thresholds pair with a **5-minute** cron
|
|
@@ -192,6 +211,10 @@ check for another client.
|
|
|
192
211
|
monitors must pass the region (see [Cloud S3 helpers](../../_underscore/features/cloud-s3-helpers.md)).
|
|
193
212
|
|
|
194
213
|
## Change history
|
|
214
|
+
- 2026-08-10 — Documented OneUptime incident/alert `{{requestBody.*}}` templating (missing
|
|
215
|
+
paths → empty string; `Not Recieved In Minutes` heartbeat spelling), discovered while
|
|
216
|
+
wiring the second all-client `_Worker_Monitor_Operations` monitor —
|
|
217
|
+
[NetSuite Integrations Monitor](./netsuite-integrations-monitor.md). (jcardinal)
|
|
195
218
|
- 2026-07-30 — Added the multi-client refinement of the payload contract: a **separate `probe`
|
|
196
219
|
token** (`OK`/`DEGRADED`) alongside `alarm`, so a partial logs-cluster outage cannot read as a
|
|
197
220
|
healthy metric, plus naming the offending clients in the body. Recorded that the previously
|
package/knowledge/INDEX.md
CHANGED
|
@@ -19,7 +19,7 @@ _Auto-generated by `knowledge.js index`. Do not hand-edit._
|
|
|
19
19
|
## 2.0 framework
|
|
20
20
|
|
|
21
21
|
- **_underscore** (_Underscore) _(framework core)_ — 48 doc(s) → [2.0/apps/_underscore/INDEX.md](2.0/apps/_underscore/INDEX.md)
|
|
22
|
-
- **worker2** (Worker) —
|
|
22
|
+
- **worker2** (Worker) — 43 doc(s) → [2.0/apps/worker2/INDEX.md](2.0/apps/worker2/INDEX.md)
|
|
23
23
|
- **api2** (API) — 22 doc(s) → [2.0/apps/api2/INDEX.md](2.0/apps/api2/INDEX.md)
|
|
24
24
|
- **dbchanges2** (Database Changes) _(framework core)_ — 8 doc(s) → [2.0/apps/dbchanges2/INDEX.md](2.0/apps/dbchanges2/INDEX.md)
|
|
25
25
|
- **toga2-supply** (TOGa Supply) — 5 doc(s) → [2.0/apps/toga2-supply/INDEX.md](2.0/apps/toga2-supply/INDEX.md)
|
package/package.json
CHANGED