Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,4 @@ To disable an OOTB launcher, create a node with the same name under `/conf/globa

Configure via **Adobe Granite Workflow Purge Configuration** OSGi factory.

Manual trigger: `curl -u admin:admin -X POST http://localhost:4502/libs/granite/operations/content/maintenance/granite_weekly/granite_workflowpurgetask.run.html`
Manual trigger: `curl -u <user>:<password> -X POST http://localhost:4502/libs/granite/operations/content/maintenance/granite_weekly/granite_workflowpurgetask.run.html` (replace credentials with your own — never use default `admin` credentials)
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,23 @@ Before starting:

## Verify Deployment

> **Note:** Replace `<user>:<password>` with your actual credentials. Never use default `admin` credentials in production or shared environments.

```bash
# Check bundle is active
curl -u admin:admin http://localhost:4502/system/console/bundles/com.example.my-bundle.json
curl -u <user>:<password> http://localhost:4502/system/console/bundles/com.example.my-bundle.json

# Check process.label registered (visible in model editor step picker)
# Navigate to: Tools → Workflow → Models → Create → add Process step → configure

# Check model synced to /var
curl -u admin:admin "http://localhost:4502/var/workflow/models/my-workflow.json"
curl -u <user>:<password> "http://localhost:4502/var/workflow/models/my-workflow.json"
```

## Start a Test Workflow via API

```bash
curl -u admin:admin -X POST \
curl -u <user>:<password> -X POST \
"http://localhost:4502/api/workflow/instances" \
-d "model=/var/workflow/models/my-workflow" \
-d "payloadType=JCR_PATH" \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ Condition format: `property=<name>,value=<value>,type=<JCR_TYPE>` (type is optio
- Check `/conf/global/settings/workflow/launcher/config/` and `/apps/settings/workflow/launcher/config/` in CRXDE Lite
- Felix Web Console → OSGi → `WorkflowLauncherListener` service
- Check `/var/workflow/launcher/` for active event registrations
- Run `curl -u admin:admin http://localhost:4502/etc/workflow/launcher.json` to list all
- Run `curl -u <user>:<password> http://localhost:4502/conf/global/settings/workflow/launcher/config.json` to list all (replace credentials with your own — never use default `admin` credentials)

## References in This Skill

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,4 @@ To disable an OOTB launcher, create a node with the same name under `/conf/globa

Configure via **Adobe Granite Workflow Purge Configuration** OSGi factory.

Manual trigger: `curl -u admin:admin -X POST http://localhost:4502/libs/granite/operations/content/maintenance/granite_weekly/granite_workflowpurgetask.run.html`
Manual trigger: `curl -u <user>:<password> -X POST http://localhost:4502/libs/granite/operations/content/maintenance/granite_weekly/granite_workflowpurgetask.run.html` (replace credentials with your own — never use default `admin` credentials)
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,23 @@ Before starting:

## Verify Deployment

> **Note:** Replace `<user>:<password>` with your actual credentials. Never use default `admin` credentials in production or shared environments.

```bash
# Check bundle is active
curl -u admin:admin http://localhost:4502/system/console/bundles/com.example.my-bundle.json
curl -u <user>:<password> http://localhost:4502/system/console/bundles/com.example.my-bundle.json

# Check process.label registered (visible in model editor step picker)
# Navigate to: Tools → Workflow → Models → Create → add Process step → configure

# Check model synced to /var
curl -u admin:admin "http://localhost:4502/var/workflow/models/my-workflow.json"
curl -u <user>:<password> "http://localhost:4502/var/workflow/models/my-workflow.json"
```

## Start a Test Workflow via API

```bash
curl -u admin:admin -X POST \
curl -u <user>:<password> -X POST \
"http://localhost:4502/api/workflow/instances" \
-d "model=/var/workflow/models/my-workflow" \
-d "payloadType=JCR_PATH" \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,4 @@ To disable an OOTB launcher, create a node with the same name under `/conf/globa

Configure via **Adobe Granite Workflow Purge Configuration** OSGi factory.

Manual trigger: `curl -u admin:admin -X POST http://localhost:4502/libs/granite/operations/content/maintenance/granite_weekly/granite_workflowpurgetask.run.html`
Manual trigger: `curl -u <user>:<password> -X POST http://localhost:4502/libs/granite/operations/content/maintenance/granite_weekly/granite_workflowpurgetask.run.html` (replace credentials with your own — never use default `admin` credentials)
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,23 @@ Before starting:

## Verify Deployment

> **Note:** Replace `<user>:<password>` with your actual credentials. Never use default `admin` credentials in production or shared environments.

```bash
# Check bundle is active
curl -u admin:admin http://localhost:4502/system/console/bundles/com.example.my-bundle.json
curl -u <user>:<password> http://localhost:4502/system/console/bundles/com.example.my-bundle.json

# Check process.label registered (visible in model editor step picker)
# Navigate to: Tools → Workflow → Models → Create → add Process step → configure

# Check model synced to /var
curl -u admin:admin "http://localhost:4502/var/workflow/models/my-workflow.json"
curl -u <user>:<password> "http://localhost:4502/var/workflow/models/my-workflow.json"
```

## Start a Test Workflow via API

```bash
curl -u admin:admin -X POST \
curl -u <user>:<password> -X POST \
"http://localhost:4502/api/workflow/instances" \
-d "model=/var/workflow/models/my-workflow" \
-d "payloadType=JCR_PATH" \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,4 @@ To disable an OOTB launcher, create a node with the same name under `/conf/globa

Configure via **Adobe Granite Workflow Purge Configuration** OSGi factory.

Manual trigger: `curl -u admin:admin -X POST http://localhost:4502/libs/granite/operations/content/maintenance/granite_weekly/granite_workflowpurgetask.run.html`
Manual trigger: `curl -u <user>:<password> -X POST http://localhost:4502/libs/granite/operations/content/maintenance/granite_weekly/granite_workflowpurgetask.run.html` (replace credentials with your own — never use default `admin` credentials)
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,23 @@ Before starting:

## Verify Deployment

> **Note:** Replace `<user>:<password>` with your actual credentials. Never use default `admin` credentials in production or shared environments.

```bash
# Check bundle is active
curl -u admin:admin http://localhost:4502/system/console/bundles/com.example.my-bundle.json
curl -u <user>:<password> http://localhost:4502/system/console/bundles/com.example.my-bundle.json

# Check process.label registered (visible in model editor step picker)
# Navigate to: Tools → Workflow → Models → Create → add Process step → configure

# Check model synced to /var
curl -u admin:admin "http://localhost:4502/var/workflow/models/my-workflow.json"
curl -u <user>:<password> "http://localhost:4502/var/workflow/models/my-workflow.json"
```

## Start a Test Workflow via API

```bash
curl -u admin:admin -X POST \
curl -u <user>:<password> -X POST \
"http://localhost:4502/api/workflow/instances" \
-d "model=/var/workflow/models/my-workflow" \
-d "payloadType=JCR_PATH" \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,21 +69,23 @@ For `/etc/workflow/models/` legacy models, the ID is `/etc/workflow/models/my-wo

## 4. HTTP Workflow API

> **Note:** Replace `<user>:<password>` with your actual credentials. Never use default `admin` credentials in production or shared environments.

```bash
# Start
curl -u admin:admin -X POST \
curl -u <user>:<password> -X POST \
"http://localhost:4502/api/workflow/instances" \
-d "model=/var/workflow/models/my-workflow" \
-d "payloadType=JCR_PATH" \
-d "payload=/content/my-site/en/home" \
-d "workflowTitle=My Test Run"

# List running instances
curl -u admin:admin \
curl -u <user>:<password> \
"http://localhost:4502/api/workflow/instances?state=RUNNING"

# Terminate an instance
curl -u admin:admin -X DELETE \
curl -u <user>:<password> -X DELETE \
"http://localhost:4502/api/workflow/instances/<instanceId>"
```

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,4 +72,4 @@ To disable an OOTB launcher, create a node with the same name under `/conf/globa

Configure via **Adobe Granite Workflow Purge Configuration** OSGi factory.

Manual trigger: `curl -u admin:admin -X POST http://localhost:4502/libs/granite/operations/content/maintenance/granite_weekly/granite_workflowpurgetask.run.html`
Manual trigger: `curl -u <user>:<password> -X POST http://localhost:4502/libs/granite/operations/content/maintenance/granite_weekly/granite_workflowpurgetask.run.html` (replace credentials with your own — never use default `admin` credentials)
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,23 @@ Before starting:

## Verify Deployment

> **Note:** Replace `<user>:<password>` with your actual credentials. Never use default `admin` credentials in production or shared environments.

```bash
# Check bundle is active
curl -u admin:admin http://localhost:4502/system/console/bundles/com.example.my-bundle.json
curl -u <user>:<password> http://localhost:4502/system/console/bundles/com.example.my-bundle.json

# Check process.label registered (visible in model editor step picker)
# Navigate to: Tools → Workflow → Models → Create → add Process step → configure

# Check model synced to /var
curl -u admin:admin "http://localhost:4502/var/workflow/models/my-workflow.json"
curl -u <user>:<password> "http://localhost:4502/var/workflow/models/my-workflow.json"
```

## Start a Test Workflow via API

```bash
curl -u admin:admin -X POST \
curl -u <user>:<password> -X POST \
"http://localhost:4502/api/workflow/instances" \
-d "model=/var/workflow/models/my-workflow" \
-d "payloadType=JCR_PATH" \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,9 +71,11 @@ wfs.startWorkflow(model, data);

**When to use:** CI/CD pipelines, external systems, shell scripts, integration tests.

> **Note:** Replace `<user>:<password>` with your actual credentials. Never use default `admin` credentials in production or shared environments.

```bash
# Start a workflow instance
curl -u admin:admin -X POST \
curl -u <user>:<password> -X POST \
"http://localhost:4502/api/workflow/instances" \
-H "Content-Type: application/x-www-form-urlencoded" \
-d "model=/var/workflow/models/my-workflow" \
Expand All @@ -82,11 +84,11 @@ curl -u admin:admin -X POST \
-d "workflowTitle=CI Triggered Review"

# Get instance details
curl -u admin:admin \
curl -u <user>:<password> \
"http://localhost:4502/api/workflow/instances/<instanceId>.json"

# Terminate a workflow
curl -u admin:admin -X DELETE \
curl -u <user>:<password> -X DELETE \
"http://localhost:4502/api/workflow/instances/<instanceId>"
```

Expand Down
1 change: 1 addition & 0 deletions skills/aem/cloud-service/skills/aem-workflow/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ This package contains workflow skills for **AEM as a Cloud Service** — coverin
| `workflow-launchers/` | Development | `cq:WorkflowLauncher` nodes: event types, glob patterns, conditions |
| `workflow-debugging/` | Production Support | Symptom → runbook, decision trees, thread pool analysis, remediation |
| `workflow-triaging/` | Production Support | Symptom classification, log patterns, Splunk queries, data gathering |
| `workflow-purge/` | Production Support | Purge Scheduler config, retention policies, bloat recovery, RUNNING/SUSPENDED cleanup |

## How To Start

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ Quick pointers used by the workflow-debugging skill. For full runbooks and proce
| Developer Console | AEM Cloud Service → Developer Console | Thread dumps, OSGi bundles, config |
| Cloud Manager Logs | Cloud Manager → Environments → Logs | error.log, access.log download/streaming |
| Workflow Console | /libs/cq/workflow/admin/console/content/instances.html | Instance status, work items, history |
| Sling Job Console | /system/console/slingjobs | Queue depth, failed jobs, active jobs |
| Sling Job Console | /system/console/slingjobs | Queue depth, failed jobs, active jobs (**local SDK only** — not accessible on Cloud Service; use Developer Console) |
| Inbox | /aem/inbox | Retry failed work items, complete tasks |

---
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,4 @@ Workflow jobs run on the **Sling Job Queue** named `com/adobe/granite/workflow/j
- OSGi config: `org.apache.sling.event.impl.jobs.queues.QueueConfigurationImpl`
- Queue name: `com\/adobe\/granite\/workflow\/job\/.*`

Monitor queue depth at: **Tools → Workflow → Instances** or `/system/console/slingevent`.
Monitor queue depth at: **Tools → Workflow → Instances**. On the local SDK, you can also check `/system/console/slingevent` (not accessible on Cloud Service environments — use Developer Console instead).
Original file line number Diff line number Diff line change
Expand Up @@ -38,21 +38,25 @@ Before starting:

## Verify Deployment

> **Note:** The examples below use local AEM SDK credentials. Replace `<user>:<password>` with your actual credentials. Never use default `admin` credentials in production or shared environments.

```bash
# Check OSGi bundle active
curl -u admin:admin http://localhost:4502/system/console/bundles/<bundle-name>.json
# Check OSGi bundle active (local SDK only — /system/console is not accessible on Cloud Service environments)
curl -u <user>:<password> http://localhost:4502/system/console/bundles/<bundle-name>.json

# Verify process.label registered
curl -u admin:admin "http://localhost:4502/libs/cq/workflow/admin/console/content/models.json"
curl -u <user>:<password> "http://localhost:4502/libs/cq/workflow/admin/console/content/models.json"

# Check model synced to /var
curl -u admin:admin "http://localhost:4502/var/workflow/models/my-workflow.json"
curl -u <user>:<password> "http://localhost:4502/var/workflow/models/my-workflow.json"
```

On Cloud Service environments, verify bundle status via **AEM Developer Console** instead of `/system/console`.

## Start a Test Workflow via API

```bash
curl -u admin:admin -X POST \
curl -u <user>:<password> -X POST \
"http://localhost:4502/api/workflow/instances" \
-d "model=/var/workflow/models/my-workflow" \
-d "payloadType=JCR_PATH" \
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,14 +33,14 @@ Workflow Instance created at /var/workflow/instances/

| Property | Type | Description |
|---|---|---|
| `eventType` | Long | `1` = NODE_ADDED, `2` = NODE_MODIFIED, `4` = NODE_REMOVED, `8` = PROPERTY_ADDED, `16` = PROPERTY_CHANGED, `32` = PROPERTY_REMOVED |
| `eventType` | Long | Bitmask of JCR event types — see [Event Type Bitmask](#event-type-bitmask) below |
| `glob` | String | Glob pattern matched against the event node path (e.g., `/content/dam(/.*)?`) |
| `nodetype` | String | JCR node type the event node must be (e.g., `dam:AssetContent`) |
| `conditions` | String[] | Additional JCR property conditions on the event node |
| `workflow` | String | Runtime path of the workflow model `/var/workflow/models/<id>` |
| `enabled` | Boolean | Whether the launcher is active |
| `description` | String | Human-readable description |
| `excludeList` | String[] | Workflow model IDs to exclude |
| `excludeList` | String[] | Runtime model paths (`/var/workflow/models/...`) whose active instances suppress this launcher — primary loop-prevention mechanism |
| `runModes` | String[] | Restrict to specific run modes (e.g., `author`) |

## Deploying a Custom Launcher on Cloud Service
Expand Down Expand Up @@ -95,6 +95,29 @@ To disable or modify an OOTB launcher (e.g., `dam_update_asset_create`):
| `dam_xmp_writeback` | NODE_MODIFIED on rendition | DAM Writeback |
| `update_page_version_*` | Node events on cq:Page jcr:content | Page Version Create |

## Event Type Bitmask

`eventType` is a bitmask combining one or more of the following values:

| Value | Name | Meaning |
|-------|------|---------|
| `1` | `NODE_ADDED` | A node was created (e.g., asset uploaded, page created) |
| `2` | `NODE_MODIFIED` | A node's properties or child nodes changed |
| `4` | `NODE_REMOVED` | A node was deleted |
| `8` | `PROPERTY_ADDED` | A property was added to a node |
| `16` | `PROPERTY_CHANGED` | A property value was changed |
| `32` | `PROPERTY_REMOVED` | A property was removed from a node |

Common combined values:

| `eventType` value | Listens for |
|---|---|
| `1` | Creation only |
| `2` | Modification only |
| `3` | Creation **or** modification (1+2) |
| `7` | Creation, modification, **or** deletion (1+2+4) |
| `18` | Property added **or** property changed (8+16) — fine-grained metadata watch |

## Event Type Combinations

To listen for both ADD and MODIFY, combine event types:
Expand Down Expand Up @@ -122,12 +145,54 @@ runModes="[publish]" <!-- only fires on Publish -->

Omit `runModes` to fire on all run modes.

## Launcher Loop Prevention

A **launcher loop** occurs when a workflow step writes back to a JCR path that matches the same launcher's `glob`, causing the launcher to fire again — repeatedly, until the queue floods.

**Scenario:** A process step updates `jcr:content/metadata` on a DAM asset. A launcher on `/content/dam(/.*)?` with `eventType=2` (NODE_MODIFIED) re-triggers the same workflow, which updates metadata again, ad infinitum.

### Prevention Strategy 1: `excludeList` (recommended)

Add the workflow model's runtime path to `excludeList`. When an instance of that model is already running against the same payload, the launcher will not enqueue a new instance.

```xml
excludeList="[/var/workflow/models/my-workflow]"
```

This is the safest approach: the launcher still fires for new content, but suppresses re-entry while the workflow is in-flight.

### Prevention Strategy 2: Narrow the `glob`

Make the glob pattern specific enough that the paths written by the workflow don't match:

```xml
<!-- Fires on original rendition upload only, not on metadata writes -->
glob="/content/dam(/.*)?/jcr:content/renditions/original"
nodetype="nt:file"
eventType="{Long}1"
```

### Prevention Strategy 3: `conditions` filter

Add a property condition that is only true on the initial trigger path, not on paths written by the workflow:

```xml
conditions="[property=dam:assetState,value=processing,type=STRING]"
```

### Detecting a Loop

Signs of a launcher loop in Cloud Manager logs:
- `WorkflowLauncherListener` enqueue messages for the same payload repeating rapidly
- Sling Job queue depth for the workflow topic growing without bound
- `numberOfQueuedJobs` metric continuously increasing

## Debugging Launchers

- **Tools → Workflow → Launchers** UI — lists all active launchers, you can enable/disable interactively
- Check `/conf/global/settings/workflow/launcher/config/` in CRXDE Lite for your deployed configs
- Check OSGi console → `WorkflowLauncherListener` service properties
- After deployment, verify via: `curl -u admin:admin http://localhost:4502/etc/workflow/launcher.json`
- After deployment, verify via: `curl -u <user>:<password> http://localhost:4502/conf/global/settings/workflow/launcher/config.json` (local SDK only; replace credentials with your own — never use default `admin` credentials)

## References in This Skill

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,4 +54,4 @@ Workflow jobs run on the **Sling Job Queue** named `com/adobe/granite/workflow/j
- OSGi config: `org.apache.sling.event.impl.jobs.queues.QueueConfigurationImpl`
- Queue name: `com\/adobe\/granite\/workflow\/job\/.*`

Monitor queue depth at: **Tools → Workflow → Instances** or `/system/console/slingevent`.
Monitor queue depth at: **Tools → Workflow → Instances**. On the local SDK, you can also check `/system/console/slingevent` (not accessible on Cloud Service environments — use Developer Console instead).
Loading