CtrlK
BlogDocsLog inGet started
Tessl Logo
PluginPublic

adobe/aem-cloud-service

All AEM as a Cloud Service skills: component development, Workflow model design, development, triggering, launchers, debugging, and triaging, Dispatcher config authoring, advisory, incident response, performance tuning, and security hardening, Rapid Development Environment (RDE) deployment, log inspection, snapshots, and troubleshooting via `aio aem rde`, Jackrabbit Oak query/index tuning (property, Lucene index definitions), and extracting/inventorying JCR queries (XPath, SQL2, QueryBuilder) across a codebase.

Quality

85%

Does it follow best practices?

Run evals on this skill

Adds up to 20 points to the overall score

View guide
SecuritybySnyk

Low

Low-risk findings worth noting

Overview
Quality
Evals
Security
Files

README.mdskills/content-distribution/

AEM as a Cloud Service Content Distribution Skills

Programmatic content publishing and distribution monitoring for Adobe Experience Manager as a Cloud Service.

Overview

These skills cover the official APIs for content replication and distribution event handling in AEM Cloud Service:

  1. Replication API (com.day.cq.replication) - Programmatic content publishing
  2. Sling Distribution Events (org.apache.sling.distribution.event) - Distribution lifecycle monitoring

Official Documentation

Skills Included

1. Replication API (replication/SKILL.md)

Use the official AEM Replication API to programmatically publish and unpublish content.

What it covers:

  • Replicator service usage with code examples
  • Publishing to Publish and Preview tiers
  • Bulk replication (with rate limits)
  • ReplicationOptions for advanced configuration
  • Replication status checks
  • Permission validation
  • Workflow integration
  • Event handling for replication events

When to use:

  • Custom OSGi services that publish content
  • Workflow process steps
  • Automated publishing pipelines
  • Integration with external systems

Official API: com.day.cq.replication.Replicator

2. Sling Distribution Event Handling (sling-distribution/SKILL.md)

Monitor and react to content distribution lifecycle events.

What it covers:

  • Distribution event topics (package created, queued, distributed, dropped, imported)
  • Event properties and metadata
  • OSGi event handler examples
  • Common use cases (alerting, cache warming, analytics)
  • Queue monitoring patterns
  • Distribution request types

When to use:

  • Monitor distribution lifecycle
  • Trigger post-distribution actions (cache warming, notifications)
  • Distribution auditing and logging
  • Handle distribution failures
  • Integration workflows

Official API: org.apache.sling.distribution.event

How They Work Together

Architecture

┌─────────────────────────────────────────────────────────┐
│ Your Code: Replication API                              │
│ replicator.replicate(session, ACTIVATE, "/content/...") │
└──────────────────────┬──────────────────────────────────┘
                       ↓
┌─────────────────────────────────────────────────────────┐
│ Sling Distribution: Underlying Transport                │
│                                                          │
│ [AGENT_PACKAGE_CREATED]   ← Event fires                 │
│         ↓                                                │
│ [AGENT_PACKAGE_QUEUED]    ← Event fires                 │
│         ↓                                                │
│ [AGENT_PACKAGE_DISTRIBUTED] ← Event fires               │
│         ↓                                                │
│ Adobe Developer Pipeline Service                        │
│         ↓                                                │
│ [IMPORTER_PACKAGE_IMPORTED] ← Event fires on target     │
└─────────────────────────────────────────────────────────┘
                       ↓
              Content is live on Publish/Preview

Workflow Example

Scenario: Publish a page and warm the CDN cache after distribution completes.

Step 1: Use Replication API to publish:

@Reference
private Replicator replicator;

// Publish content
replicator.replicate(session, ReplicationActionType.ACTIVATE, "/content/mysite/en/page");

Step 2: Listen for distribution completion:

@Component(
    service = EventHandler.class,
    property = {
        org.osgi.service.event.EventConstants.EVENT_TOPIC + "=" + 
            DistributionEventTopics.IMPORTER_PACKAGE_IMPORTED
    }
)
public class CacheWarmingHandler implements EventHandler {
    
    @Override
    public void handleEvent(Event event) {
        String[] paths = (String[]) event.getProperty(
            DistributionEventProperties.DISTRIBUTION_PATHS
        );
        
        for (String path : paths) {
            warmCache(path);  // Custom cache warming logic
        }
    }
}

Key Differences from AEM 6.x

AspectAEM 6.xAEM Cloud Service
Replication APIcom.day.cq.replication.Replicator✅ Same API available
TransportDirect JCR replicationSling Distribution via Adobe Developer pipeline
AgentsManual configurationAutomatic (managed by Adobe)
Preview TierNot availableAvailable with agent filtering
Distribution EventsLimitedFull lifecycle events via org.apache.sling.distribution.event

Rate Limits and Constraints

Replication API Limits

ConstraintLimit
Paths per API call (recommended)100
Paths per API call (above 100)System auto-splits into non-transactional chunks
Transactional guarantee≤100 paths only
Payload size10 MB maximum

Best Practices

  1. Respect rate limits: ≤100 paths per call for transactional guarantee
  2. Use workflow for large trees: Tree Activation workflow step for large hierarchical content trees
  3. Handle failures gracefully: Always catch ReplicationException
  4. Use service users: Never replicate with admin credentials
  5. Publish only what's needed: Avoid unnecessary bulk operations
  6. Monitor events: Use Sling Distribution events for observability

Common Use Cases

Use Case 1: Auto-Publish Content Fragments

// Listen for content fragment changes
@Component(service = EventHandler.class, property = {
    org.osgi.service.event.EventConstants.EVENT_TOPIC + "=" + 
        SlingConstants.TOPIC_RESOURCE_CHANGED
})
public class AutoPublishHandler implements EventHandler {
    
    @Reference
    private Replicator replicator;
    
    @Reference
    private ResourceResolverFactory resolverFactory;
    
    @Override
    public void handleEvent(Event event) {
        String path = (String) event.getProperty(SlingConstants.PROPERTY_PATH);
        
        if (isContentFragment(path)) {
            try (ResourceResolver resolver = getServiceResolver()) {
                Session session = resolver.adaptTo(Session.class);
                replicator.replicate(session, ReplicationActionType.ACTIVATE, path);
            } catch (Exception e) {
                LOG.error("Auto-publish failed", e);
            }
        }
    }
    
    private ResourceResolver getServiceResolver() throws LoginException {
        Map<String, Object> param = Map.of(
            ResourceResolverFactory.SUBSERVICE, "contentPublisher"
        );
        return resolverFactory.getServiceResourceResolver(param);
    }
    
    private boolean isContentFragment(String path) {
        return path != null && path.startsWith("/content/dam") && 
               path.contains("/jcr:content");
    }
}

Use Case 2: Alert on Distribution Failures

// Monitor for dropped packages
@Component(service = EventHandler.class, property = {
    org.osgi.service.event.EventConstants.EVENT_TOPIC + "=" + 
        DistributionEventTopics.AGENT_PACKAGE_DROPPED
})
public class FailureAlertHandler implements EventHandler {
    
    @Override
    public void handleEvent(Event event) {
        String packageId = (String) event.getProperty(
            DistributionEventProperties.DISTRIBUTION_PACKAGE_ID
        );
        String[] paths = (String[]) event.getProperty(
            DistributionEventProperties.DISTRIBUTION_PATHS
        );
        
        LOG.error("Distribution failed: packageId={}, paths={}", 
            packageId, String.join(",", paths));
        
        // Send alert to operations team
        alertService.sendAlert("Distribution failure", packageId);
    }
}

Use Case 3: CDN Cache Warming

// Warm cache after successful distribution
@Component(service = EventHandler.class, property = {
    org.osgi.service.event.EventConstants.EVENT_TOPIC + "=" + 
        DistributionEventTopics.IMPORTER_PACKAGE_IMPORTED
})
public class CacheWarmingHandler implements EventHandler {
    
    @Override
    public void handleEvent(Event event) {
        String[] paths = (String[]) event.getProperty(
            DistributionEventProperties.DISTRIBUTION_PATHS
        );
        
        for (String path : paths) {
            String url = convertToPublicUrl(path);
            httpClient.execute(new HttpGet(url));  // Warm cache
        }
    }
}

Use Case 4: Publish to Preview for Approval Workflow

// Workflow step: Publish to Preview for review
@Component(service = WorkflowProcess.class, property = {
    "process.label=Publish to Preview for Review"
})
public class PublishToPreviewStep implements WorkflowProcess {
    
    @Reference
    private Replicator replicator;
    
    @Override
    public void execute(WorkItem workItem, WorkflowSession workflowSession, 
                       MetaDataMap args) throws WorkflowException {
        
        String payloadPath = workItem.getWorkflowData().getPayload().toString();
        Session session = workflowSession.adaptTo(Session.class);
        
        // Create options to target Preview tier
        ReplicationOptions options = new ReplicationOptions();
        options.setFilter(agent -> "preview".equals(agent.getId()));
        
        try {
            replicator.replicate(
                session,
                ReplicationActionType.ACTIVATE,
                payloadPath,
                options
            );
        } catch (ReplicationException e) {
            throw new WorkflowException("Failed to publish to Preview", e);
        }
    }
}

Quick Reference

Replication API - Key Classes

// Inject the service
@Reference
private Replicator replicator;

// Single path
replicator.replicate(session, ReplicationActionType.ACTIVATE, "/content/page");

// Multiple paths
replicator.replicate(session, ReplicationActionType.ACTIVATE, 
    new String[]{"/content/page1", "/content/page2"}, null);

// With options
ReplicationOptions options = new ReplicationOptions();
options.setFilter(agent -> "preview".equals(agent.getId()));
replicator.replicate(session, ReplicationActionType.ACTIVATE, "/content/page", options);

// Check status
ReplicationStatus status = replicator.getReplicationStatus(session, "/content/page");
boolean isPublished = status != null && status.isActivated();

Distribution Events - Key Topics

// Listen for events
@Component(service = EventHandler.class, property = {
    org.osgi.service.event.EventConstants.EVENT_TOPIC + "=" + 
        DistributionEventTopics.AGENT_PACKAGE_CREATED,
    org.osgi.service.event.EventConstants.EVENT_TOPIC + "=" + 
        DistributionEventTopics.AGENT_PACKAGE_QUEUED,
    org.osgi.service.event.EventConstants.EVENT_TOPIC + "=" + 
        DistributionEventTopics.AGENT_PACKAGE_DISTRIBUTED,
    org.osgi.service.event.EventConstants.EVENT_TOPIC + "=" + 
        DistributionEventTopics.AGENT_PACKAGE_DROPPED,
    org.osgi.service.event.EventConstants.EVENT_TOPIC + "=" + 
        DistributionEventTopics.IMPORTER_PACKAGE_IMPORTED
})
public class MyDistributionHandler implements EventHandler {
    
    @Override
    public void handleEvent(Event event) {
        String packageId = (String) event.getProperty(
            DistributionEventProperties.DISTRIBUTION_PACKAGE_ID
        );
        String[] paths = (String[]) event.getProperty(
            DistributionEventProperties.DISTRIBUTION_PATHS
        );
        // Handle event
    }
}

Troubleshooting

Common Issues

IssueCauseSolution
ReplicationExceptionPermission deniedCheck service user has crx:replicate permission
Content not appearingWrong tier selectedVerify agent filter targets correct tier (preview vs publish)
Event handler not firingWrong event topicUse exact constants from DistributionEventTopics
"Too many paths" error>100 paths lose transactional guaranteeUse ≤100 for atomicity; system auto-splits larger sets

Debug Checklist

  1. Replication fails:

    • Check logs for ReplicationException
    • Verify user has crx:replicate permission on content path
    • Check Sling jobs console: /system/console/slingjobs
  2. Events not firing:

    • Verify component is active: /system/console/components
    • Check event topic matches exactly
    • Verify OSGi event handler properties
  3. Content not on target tier:

    • Check replication status: replicator.getReplicationStatus()
    • Verify agent filter targets correct tier
    • Check distribution logs in Cloud Manager

References

  • Replication Skill: replication/SKILL.md
  • Sling Distribution Skill: sling-distribution/SKILL.md
  • Official Javadoc: https://developer.adobe.com/experience-manager/reference-materials/cloud-service/javadoc/
  • Adobe Documentation: https://experienceleague.adobe.com/docs/experience-manager-cloud-service/content/operations/replication.html

skills

content-distribution

README.md

SKILL.md

README.md

tile.json