content-distribution

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

AEM Cloud Service Content Distribution

AEM Cloud Service内容分发

Beta Skill: This skill is in beta and under active development. Results should be reviewed carefully before use in production. Report issues at https://github.com/adobe/skills/issues
Programmatic content publishing and distribution monitoring using official AEM Cloud Service APIs.
Beta Skill: 此技能处于测试阶段,正在积极开发中。 在生产环境中使用前,请仔细检查结果。 请访问 https://github.com/adobe/skills/issues 提交问题
使用官方AEM Cloud Service API实现程序化内容发布与分发监控。

When to Use This Skill

何时使用此技能

Use this skill collection for:
  • Programmatic publishing: Publish content via
    Replicator
    API
  • Distribution monitoring: Track distribution lifecycle events
  • Automated workflows: Integration with workflow process steps
  • Event handling: React to distribution events (failures, completions)
  • Custom publishing logic: Bulk operations, Preview tier publishing
此技能集合适用于以下场景:
  • 程序化发布:通过
    Replicator
    API发布内容
  • 分发监控:跟踪分发生命周期事件
  • 自动化工作流:与工作流流程步骤集成
  • 事件处理:响应分发事件(失败、完成)
  • 自定义发布逻辑:批量操作、预览环境发布

Sub-Skills

子技能

This is a parent skill that routes to specialized sub-skills based on your task:
TaskSub-SkillFile
Programmatically publish/unpublish contentReplication APIreplication/SKILL.md
Monitor distribution events and lifecycleSling Distribution Eventssling-distribution/SKILL.md
这是一个父技能,会根据你的任务路由到专门的子技能:
任务子技能文件
程序化发布/取消发布内容Replication APIreplication/SKILL.md
监控分发事件与生命周期Sling Distribution Eventssling-distribution/SKILL.md

Quick Decision Guide

快速决策指南

Choose Replication API when you need to:
  • Publish content from custom OSGi services
  • Integrate publishing into workflow steps
  • Perform bulk publishing operations
  • Publish to Preview tier for review
  • Check replication status programmatically
Choose Sling Distribution Events when you need to:
  • Monitor distribution lifecycle (created, queued, distributed, imported)
  • React to distribution failures
  • Trigger post-distribution actions (cache warming, notifications)
  • Audit distribution operations
  • Track distribution metrics
选择Replication API当你需要:
  • 从自定义OSGi服务发布内容
  • 将发布集成到工作流步骤中
  • 执行批量发布操作
  • 发布到预览环境供审核
  • 程序化检查复制状态
选择Sling Distribution Events当你需要:
  • 监控分发生命周期(创建、排队、分发、导入)
  • 响应分发失败
  • 触发分发后操作(缓存预热、通知)
  • 审计分发操作
  • 跟踪分发指标

Official APIs

官方API

Both skills use official, supported AEM Cloud Service APIs:
  1. Replication API:
    com.day.cq.replication
  2. Sling Distribution API:
    org.apache.sling.distribution
两个技能均使用官方支持的AEM Cloud Service API:
  1. Replication API
    com.day.cq.replication
  2. Sling Distribution API
    org.apache.sling.distribution

Architecture Overview

架构概述

┌──────────────────────────────────────────────────┐
│ Replication API (Your Code)                     │
│ com.day.cq.replication.Replicator                │
│                                                  │
│ replicator.replicate(session, ACTIVATE, path)   │
└────────────────────┬─────────────────────────────┘
┌──────────────────────────────────────────────────┐
│ Sling Distribution (Underlying Transport)       │
│ org.apache.sling.distribution                    │
│                                                  │
│ [AGENT_PACKAGE_CREATED]   ← Distribution events │
│          ↓                   fire at each stage  │
│ [AGENT_PACKAGE_QUEUED]                          │
│          ↓                                       │
│ [AGENT_PACKAGE_DISTRIBUTED]                     │
│          ↓                                       │
│ Adobe Developer Pipeline Service                │
│          ↓                                       │
│ [IMPORTER_PACKAGE_IMPORTED]                     │
└──────────────────────────────────────────────────┘
         Content live on Publish/Preview
┌──────────────────────────────────────────────────┐
│ Replication API (Your Code)                     │
│ com.day.cq.replication.Replicator                │
│                                                  │
│ replicator.replicate(session, ACTIVATE, path)   │
└────────────────────┬─────────────────────────────┘
┌──────────────────────────────────────────────────┐
│ Sling Distribution (Underlying Transport)       │
│ org.apache.sling.distribution                    │
│                                                  │
│ [AGENT_PACKAGE_CREATED]   ← Distribution events │
│          ↓                   fire at each stage  │
│ [AGENT_PACKAGE_QUEUED]                          │
│          ↓                                       │
│ [AGENT_PACKAGE_DISTRIBUTED]                     │
│          ↓                                       │
│ Adobe Developer Pipeline Service                │
│          ↓                                       │
│ [IMPORTER_PACKAGE_IMPORTED]                     │
└──────────────────────────────────────────────────┘
         Content live on Publish/Preview

How It Works

工作原理

  1. Your code calls
    Replicator.replicate()
    to publish content
  2. Sling Distribution packages content and fires
    AGENT_PACKAGE_CREATED
    event
  3. Package is queued and
    AGENT_PACKAGE_QUEUED
    event fires
  4. Package is sent to Adobe Developer pipeline and
    AGENT_PACKAGE_DISTRIBUTED
    event fires
  5. Target tier imports content and
    IMPORTER_PACKAGE_IMPORTED
    event fires
  6. Content is live on target tier (Publish or Preview)
  1. 你的代码调用
    Replicator.replicate()
    发布内容
  2. Sling Distribution打包内容并触发
    AGENT_PACKAGE_CREATED
    事件
  3. 包被排队并触发
    AGENT_PACKAGE_QUEUED
    事件
  4. 包被发送到Adobe Developer管道并触发
    AGENT_PACKAGE_DISTRIBUTED
    事件
  5. 目标环境导入内容并触发
    IMPORTER_PACKAGE_IMPORTED
    事件
  6. 内容在目标环境(发布或预览)上线

Common Patterns

常见模式

Pattern 1: Publish and Monitor

模式1:发布并监控

Publish content and track when it goes live:
java
// Step 1: Publish using Replication API
@Reference
private Replicator replicator;

public void publishContent(Session session, String path) throws ReplicationException {
    replicator.replicate(session, ReplicationActionType.ACTIVATE, path);
}

// Step 2: Monitor completion using Distribution Events
@Component(service = EventHandler.class, property = {
    org.osgi.service.event.EventConstants.EVENT_TOPIC + "=" + 
        DistributionEventTopics.IMPORTER_PACKAGE_IMPORTED
})
public class PublishCompletionHandler implements EventHandler {
    
    @Override
    public void handleEvent(Event event) {
        String[] paths = (String[]) event.getProperty(
            DistributionEventProperties.DISTRIBUTION_PATHS
        );
        
        LOG.info("Content is now live: {}", String.join(",", paths));
        // Trigger post-publish actions (cache warming, notifications, etc.)
    }
}
发布内容并跟踪其上线时间:
java
// Step 1: Publish using Replication API
@Reference
private Replicator replicator;

public void publishContent(Session session, String path) throws ReplicationException {
    replicator.replicate(session, ReplicationActionType.ACTIVATE, path);
}

// Step 2: Monitor completion using Distribution Events
@Component(service = EventHandler.class, property = {
    org.osgi.service.event.EventConstants.EVENT_TOPIC + "=" + 
        DistributionEventTopics.IMPORTER_PACKAGE_IMPORTED
})
public class PublishCompletionHandler implements EventHandler {
    
    @Override
    public void handleEvent(Event event) {
        String[] paths = (String[]) event.getProperty(
            DistributionEventProperties.DISTRIBUTION_PATHS
        );
        
        LOG.info("Content is now live: {}", String.join(",", paths));
        // Trigger post-publish actions (cache warming, notifications, etc.)
    }
}

Pattern 2: Preview-First Workflow

模式2:预览优先工作流

Publish to Preview for approval, then to Publish:
java
// Workflow Step 1: Publish to Preview
public void publishToPreview(Session session, String path) throws ReplicationException {
    ReplicationOptions options = new ReplicationOptions();
    options.setFilter(agent -> "preview".equals(agent.getId()));
    
    replicator.replicate(session, ReplicationActionType.ACTIVATE, path, options);
}

// Workflow Step 2: After approval, publish to Publish tier
public void publishToProduction(Session session, String path) throws ReplicationException {
    ReplicationOptions options = new ReplicationOptions();
    options.setFilter(agent -> "publish".equals(agent.getId()));
    
    replicator.replicate(session, ReplicationActionType.ACTIVATE, path, options);
}
先发布到预览环境审批,再发布到生产环境:
java
// Workflow Step 1: Publish to Preview
public void publishToPreview(Session session, String path) throws ReplicationException {
    ReplicationOptions options = new ReplicationOptions();
    options.setFilter(agent -> "preview".equals(agent.getId()));
    
    replicator.replicate(session, ReplicationActionType.ACTIVATE, path, options);
}

// Workflow Step 2: After approval, publish to Publish tier
public void publishToProduction(Session session, String path) throws ReplicationException {
    ReplicationOptions options = new ReplicationOptions();
    options.setFilter(agent -> "publish".equals(agent.getId()));
    
    replicator.replicate(session, ReplicationActionType.ACTIVATE, path, options);
}

Pattern 3: Auto-Publish with Failure Handling

模式3:自动发布与故障处理

Auto-publish content and alert on failures:
java
// Publish handler
@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;
    
    @Override
    public void handleEvent(Event event) {
        String path = (String) event.getProperty(SlingConstants.PROPERTY_PATH);
        
        if (shouldAutoPublish(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);
            }
        }
    }
}

// Failure monitoring
@Component(service = EventHandler.class, property = {
    org.osgi.service.event.EventConstants.EVENT_TOPIC + "=" + 
        DistributionEventTopics.AGENT_PACKAGE_DROPPED
})
public class FailureAlertHandler implements EventHandler {
    
    @Reference
    private AlertService alertService;
    
    @Override
    public void handleEvent(Event event) {
        String packageId = (String) event.getProperty(
            DistributionEventProperties.DISTRIBUTION_PACKAGE_ID
        );
        
        alertService.sendAlert("Distribution failed", packageId);
    }
}
自动发布内容并在故障时发出警报:
java
// Publish handler
@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;
    
    @Override
    public void handleEvent(Event event) {
        String path = (String) event.getProperty(SlingConstants.PROPERTY_PATH);
        
        if (shouldAutoPublish(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);
            }
        }
    }
}

// Failure monitoring
@Component(service = EventHandler.class, property = {
    org.osgi.service.event.EventConstants.EVENT_TOPIC + "=" + 
        DistributionEventTopics.AGENT_PACKAGE_DROPPED
})
public class FailureAlertHandler implements EventHandler {
    
    @Reference
    private AlertService alertService;
    
    @Override
    public void handleEvent(Event event) {
        String packageId = (String) event.getProperty(
            DistributionEventProperties.DISTRIBUTION_PACKAGE_ID
        );
        
        alertService.sendAlert("Distribution failed", packageId);
    }
}

Rate Limits and Constraints

速率限制与约束

ConstraintLimitImpact
Paths per API call (recommended)100Transactional guarantee; system auto-splits above this
Payload size10 MBExcluding binaries
Note:
ReplicationOptions.setUseAtomicCalls()
is
@Deprecated
/ "no longer required" per the Cloud Service Javadoc — the system handles auto-bucketing automatically for >100 paths.
Best Practice: For large hierarchical content trees, use the Tree Activation workflow step instead of custom code.
约束限制影响
每次API调用的路径数(推荐)100事务性保证;超过此数量系统会自动拆分
负载大小10 MB不包含二进制文件
注意:根据Cloud Service Javadoc,
ReplicationOptions.setUseAtomicCalls()
已被
@Deprecated
/不再需要——系统会自动对超过100条路径的请求进行自动分桶处理。
最佳实践:对于大型层级内容树,使用Tree Activation工作流步骤而非自定义代码。

Key Differences from AEM 6.x

与AEM 6.x的主要差异

FeatureAEM 6.xAEM Cloud Service
Replication API
com.day.cq.replication.Replicator
✅ Same API
Replication agentsManual configuration✅ Automatic (managed by Adobe)
Transport mechanismDirect JCR replication✅ Sling Distribution via Adobe pipeline
Preview tierNot available✅ Available (requires agent filtering)
Distribution eventsLimited✅ Full lifecycle via
org.apache.sling.distribution.event
Agent configurationManual OSGi config❌ Not exposed (managed by Adobe)
特性AEM 6.xAEM Cloud Service
Replication API
com.day.cq.replication.Replicator
✅ 相同API
复制代理手动配置✅ 自动配置(由Adobe管理)
传输机制直接JCR复制✅ 通过Adobe管道的Sling Distribution
预览环境不可用✅ 可用(需要代理过滤)
分发事件有限✅ 通过
org.apache.sling.distribution.event
提供完整生命周期
代理配置手动OSGi配置❌ 不对外暴露(由Adobe管理)

When NOT to Use These Skills

何时不使用这些技能

Use UI workflows instead when:
  • Publishing small amounts of content manually
  • One-off publishing operations
  • Content authors can use Quick Publish or Manage Publication
Use Tree Activation workflow when:
  • Publishing large hierarchical content trees
  • Bulk operations across hundreds of paths and no custom logic is needed
改用UI工作流当:
  • 手动发布少量内容
  • 一次性发布操作
  • 内容作者可使用快速发布或管理发布功能
改用Tree Activation工作流当:
  • 发布大型层级内容树
  • 需要跨数百条路径执行批量操作且无需自定义逻辑

Quick Reference

快速参考

Replication API Basics

Replication API基础

java
// Inject service
@Reference
private Replicator replicator;

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

// Unpublish
replicator.replicate(session, ReplicationActionType.DEACTIVATE, "/content/mysite/page");

// Bulk publish (≤100 for transactional guarantee)
replicator.replicate(session, ReplicationActionType.ACTIVATE, 
    new String[]{"/content/page1", "/content/page2"}, null);

// Publish to Preview
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();
java
// Inject service
@Reference
private Replicator replicator;

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

// Unpublish
replicator.replicate(session, ReplicationActionType.DEACTIVATE, "/content/mysite/page");

// Bulk publish (≤100 for transactional guarantee)
replicator.replicate(session, ReplicationActionType.ACTIVATE, 
    new String[]{"/content/page1", "/content/page2"}, null);

// Publish to Preview
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 Event Handling Basics

分发事件处理基础

java
// Listen for distribution 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_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 DistributionMonitor implements EventHandler {
    
    @Override
    public void handleEvent(Event event) {
        String topic = event.getTopic();
        String packageId = (String) event.getProperty(
            DistributionEventProperties.DISTRIBUTION_PACKAGE_ID
        );
        String[] paths = (String[]) event.getProperty(
            DistributionEventProperties.DISTRIBUTION_PATHS
        );
        
        // Handle event based on topic
        if (DistributionEventTopics.AGENT_PACKAGE_DROPPED.equals(topic)) {
            LOG.error("Distribution failed: {}", packageId);
        } else if (DistributionEventTopics.IMPORTER_PACKAGE_IMPORTED.equals(topic)) {
            LOG.info("Content is live: {}", String.join(",", paths));
        }
    }
}
java
// Listen for distribution 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_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 DistributionMonitor implements EventHandler {
    
    @Override
    public void handleEvent(Event event) {
        String topic = event.getTopic();
        String packageId = (String) event.getProperty(
            DistributionEventProperties.DISTRIBUTION_PACKAGE_ID
        );
        String[] paths = (String[]) event.getProperty(
            DistributionEventProperties.DISTRIBUTION_PATHS
        );
        
        // Handle event based on topic
        if (DistributionEventTopics.AGENT_PACKAGE_DROPPED.equals(topic)) {
            LOG.error("Distribution failed: {}", packageId);
        } else if (DistributionEventTopics.IMPORTER_PACKAGE_IMPORTED.equals(topic)) {
            LOG.info("Content is live: {}", String.join(",", paths));
        }
    }
}

Best Practices

最佳实践

  1. Use the right API: Replication API for publishing, Distribution events for monitoring
  2. Respect rate limits: ≤100 paths for transactional guarantee
  3. Handle failures: Always catch
    ReplicationException
    , monitor
    AGENT_PACKAGE_DROPPED
    events
  4. Use service users: Never use admin credentials
  5. Filter events appropriately: Only listen to events you need
  6. Validate permissions: Call
    replicator.checkPermission()
    before replication
  7. Publish only what's needed: Avoid unnecessary bulk operations
  1. 使用正确的API:发布用Replication API,监控用分发事件
  2. 遵守速率限制:≤100条路径以保证事务性
  3. 处理故障:始终捕获
    ReplicationException
    ,监控
    AGENT_PACKAGE_DROPPED
    事件
  4. 使用服务用户:切勿使用管理员凭据
  5. 适当过滤事件:仅监听你需要的事件
  6. 验证权限:复制前调用
    replicator.checkPermission()
  7. 仅发布必要内容:避免不必要的批量操作

Troubleshooting

故障排除

Replication Issues

复制问题

IssueSolution
ReplicationException
Check service user has
crx:replicate
permission
Content not on target tierVerify agent filter, check replication status
"Too many paths" errorUse ≤100 paths for transactional guarantee, or pass all paths — system auto-splits
问题解决方案
ReplicationException
检查服务用户是否拥有
crx:replicate
权限
内容未出现在目标环境验证代理过滤器,检查复制状态
"路径过多"错误使用≤100条路径以保证事务性,或直接传入所有路径——系统会自动拆分

Event Handling Issues

事件处理问题

IssueSolution
Event handler not firingVerify event topic constant matches exactly
Missing event propertiesAlways null-check event properties
Handler slowing distributionUse async job processing, don't block
问题解决方案
事件处理器未触发验证事件主题常量完全匹配
缺少事件属性始终对事件属性进行空值检查
处理器拖慢分发速度使用异步作业处理,不要阻塞

Detailed Documentation

详细文档

For detailed examples, code samples, and advanced usage:
  • Replication API: See replication/SKILL.md
  • Sling Distribution Events: See sling-distribution/SKILL.md
如需详细示例、代码样例和高级用法:
  • Replication API:查看 replication/SKILL.md
  • Sling Distribution Events:查看 sling-distribution/SKILL.md

References

参考资料