AEM in 40 Days
CalendarPhase 5 · Advanced Development

Day 33 of 40

Workflows, Search and Indexing

Automating content processes and making queries fast

~55 min read5 videos6 source pages

By the end of today you should be able to

  1. Build a workflow model and explain the common step types
  2. Explain how workflows are launched and where instances live
  3. Write a query and choose the right index for it
  4. Diagnose and fix a repository traversal warning

Workflows

A workflow automates a content process: review and approval, scheduled publication, asset processing, translation handoff. Models are built in the Workflow Model editor (Tools → Workflow → Models) and stored under /conf.

Step types you will actually use:

  • Participant step — assigns a task to a person or group and waits. This is the human approval gate; the task appears in their Inbox.
  • Dynamic participant step — the assignee is chosen at runtime by a chooser class.
  • Process step — runs Java. Implement WorkflowProcess and register it as an OSGi service with a process.label property so it appears in the editor.
  • OR split / AND split — branch conditionally, or run branches in parallel.
  • Container step — invoke another workflow model as a sub-process.
  • Goto step — jump, enabling loops.
@Component(service = WorkflowProcess.class,
           property = {"process.label=WKND Notify Editor"})
public class NotifyEditorProcess implements WorkflowProcess {

    @Override
    public void execute(WorkItem item, WorkflowSession session,
                        MetaDataMap args) throws WorkflowException {
        String path = item.getWorkflowData().getPayload().toString();
        // ...
    }
}

Workflows start manually, via a launcher (a rule watching a path and node type for a change), or from code. Running instances live under /var/workflow/instances, and their volume is a real operational concern — a launcher on a broad path can generate thousands of instances and fill the repository. Purge configuration exists for exactly this reason.

Launchers are easy to overreach

A launcher on /content for any cq:PageContent modification fires on every save by every author. Scope launchers to the narrowest path and condition that achieves the goal, and check /var/workflow/instances after deploying one.

Querying

AEM offers several query languages over Oak. In practice:

  • QueryBuilder — AEM's map-based API. Convenient, and what most AEM code uses.
  • JCR-SQL2 — the underlying standard query language. More explicit, easier to reason about for performance.
  • XPath — legacy, still seen in older code.
Map<String, String> params = new HashMap<>();
params.put("path", "/content/wknd");
params.put("type", "cq:Page");
params.put("property", "jcr:content/cq:template");
params.put("property.value", "/conf/wknd/settings/wcm/templates/article-page");
params.put("p.limit", "20");

Query query = queryBuilder.createQuery(
        PredicateGroup.create(params), session);
SearchResult result = query.getResult();

Indexes

Oak does not index everything by default. An unindexed query traverses — walking nodes one by one — which is fine over a hundred nodes and catastrophic over a million.

Index types:

  • Property index — for exact matches on a specific property. Cheap and fast.
  • Lucene property index — the general workhorse, supporting full-text and complex conditions.
  • Ordered index — for range queries and sorting.

Custom indexes are defined under /oak:index and ship in ui.apps. On Cloud Service, index definitions must be named with a package suffix (damAssetLucene-8-custom-1 style) and are deployed and reindexed by the pipeline.

Finding traversals

Watch error.log for warnings about traversing a large number of nodes — Oak logs them explicitly. Cloud Service also surfaces traversal risks in the Developer Console. Every one of those warnings is a query that will get slower as content grows.

Practical rules that prevent most index problems:

  • Always constrain by path. A query over all of /content is rarely what you want.
  • Always set a limit. Unbounded result sets are a memory risk.
  • Prefer an existing index. Check what is already defined before adding one; indexes cost write performance and storage.
  • Explain the query. The Query Performance tool (/libs/granite/operations/content/diagnosistools/queryPerformance.html) shows the execution plan and whether an index was used.
Today's takeaway

Scope launchers narrowly and watch instance volume. Constrain every query by path and limit, and treat a traversal warning as a bug rather than noise.

Watch

Adobe's own videos for this topic. They load only when you press play.

AEM 6.5 Workflow Enhancements Feature Video
Workflow Model Editor
Inbox Collaboration
Search and Indexing - Moving to AEM CS
How to investigate indexing related issues

Read on Experience League

The primary sources these notes are drawn from.

Your notes

Saved automatically to this browser.

Check yourself

10 questions on today's material. 80% to pass.

Take the quiz