Skip to main content
Level 2
Feb 12, 2026 9:47 PM UTC
Solved

AMS to AEMaaCS Migration - Performing certain job on Publish tier

We are migrating our AEM environment from AMS to AEM as a Cloud Service (AEMaaCS). In our current production environment (AMS), we have 1 Author instance and 4 Publisher instances. One of the custom feature: Whenever a Topic is published (replicated), we need to send Topic content to an external application (from publisher only).

Currently, we compare configured sling id with 4 publisher’s sling ID and ensuring sending the content from 1 publisher only. 

After AEMaaCS migration, how we can achieve the same functionality (identify 1 pod publisher out of multi pod publishers) and then send the published content to external app from 1 pod publisher only.

giuseppebaglio
giuseppebaglioAccepted solution
Level 10
Feb 13, 2026 8:52 AM UTC

hi ​@helloosuman,

if possible I’d leverage the author instance as single orchestrator for sending content to the external application because it would really simplify the architecture logic and possible corner cases.

@Component(
service = EventHandler.class,
immediate = true,
property = {
EventConstants.EVENT_TOPIC + "=org/apache/sling/distribution/agent/package/distributed"
}
)
public class TopicReplicationHandler implements EventHandler {

@Override
public void handleEvent(Event event) {
// Extract path and verify it's a Topic
String[] paths = (String[]) event.getProperty("paths");

// Verify it's an activation/publish event
// Send to external application from Author (only once)
sendToExternalApp(paths);
}

private void sendToExternalApp(String[] paths) {
// Your external API call logic here
// This executes only once from Author
}
}


If Author is not viable then you can leverage Discovery Service to find the topology leader within a EventHandler:

@Component(
service = EventHandler.class,
immediate = true,
property = {
EventConstants.EVENT_TOPIC + "=" + ReplicationAction.EVENT_TOPIC
}
)
public class LeaderElectedTopicHandler implements EventHandler {

private static final Logger LOG = LoggerFactory.getLogger(LeaderElectedTopicHandler.class);

@Reference private DiscoveryService discoveryService;

@Override
public void handleEvent(Event event) {
// Only process if this instance is the leader
if (!isLeaderInstance()) {
LOG.debug("Skipping event - not the leader");
return;
}

// Process replication event and send to external app
sendToExternalApp(event);
}

/**
* Check if this instance is the cluster leader
*/
private boolean isLeaderInstance() {
try {
TopologyView topology = discoveryService.getTopology();
if (topology == null) {
LOG.warn("Topology is null - cannot determine leader status");
return false;
}

InstanceDescription localInstance = topology.getLocalInstance();
if (localInstance == null) {
LOG.warn("Local instance is null - cannot determine leader status");
return false;
}

boolean isLeader = localInstance.isLeader();
LOG.debug("Leader status: {}, Sling ID: {}",
isLeader, localInstance.getSlingId());

return isLeader;

} catch (Exception e) {
LOG.error("Error determining leader status", e);
return false;
}
}
}

This should works but, as corner case to evaluate, the topology can change during deployments and there may be brief periods with no leader or multiple leaders during transitions.

2 replies

giuseppebaglio
giuseppebaglioAccepted solution
Level 10
Feb 13, 2026 8:52 AM UTC

hi ​@helloosuman,

if possible I’d leverage the author instance as single orchestrator for sending content to the external application because it would really simplify the architecture logic and possible corner cases.

@Component(
service = EventHandler.class,
immediate = true,
property = {
EventConstants.EVENT_TOPIC + "=org/apache/sling/distribution/agent/package/distributed"
}
)
public class TopicReplicationHandler implements EventHandler {

@Override
public void handleEvent(Event event) {
// Extract path and verify it's a Topic
String[] paths = (String[]) event.getProperty("paths");

// Verify it's an activation/publish event
// Send to external application from Author (only once)
sendToExternalApp(paths);
}

private void sendToExternalApp(String[] paths) {
// Your external API call logic here
// This executes only once from Author
}
}


If Author is not viable then you can leverage Discovery Service to find the topology leader within a EventHandler:

@Component(
service = EventHandler.class,
immediate = true,
property = {
EventConstants.EVENT_TOPIC + "=" + ReplicationAction.EVENT_TOPIC
}
)
public class LeaderElectedTopicHandler implements EventHandler {

private static final Logger LOG = LoggerFactory.getLogger(LeaderElectedTopicHandler.class);

@Reference private DiscoveryService discoveryService;

@Override
public void handleEvent(Event event) {
// Only process if this instance is the leader
if (!isLeaderInstance()) {
LOG.debug("Skipping event - not the leader");
return;
}

// Process replication event and send to external app
sendToExternalApp(event);
}

/**
* Check if this instance is the cluster leader
*/
private boolean isLeaderInstance() {
try {
TopologyView topology = discoveryService.getTopology();
if (topology == null) {
LOG.warn("Topology is null - cannot determine leader status");
return false;
}

InstanceDescription localInstance = topology.getLocalInstance();
if (localInstance == null) {
LOG.warn("Local instance is null - cannot determine leader status");
return false;
}

boolean isLeader = localInstance.isLeader();
LOG.debug("Leader status: {}, Sling ID: {}",
isLeader, localInstance.getSlingId());

return isLeader;

} catch (Exception e) {
LOG.error("Error determining leader status", e);
return false;
}
}
}

This should works but, as corner case to evaluate, the topology can change during deployments and there may be brief periods with no leader or multiple leaders during transitions.

Translate
Level 2
Feb 13, 2026 6:05 PM UTC

giuseppebaglio I shall try your suggestion for publisher and let you know how it went. Thank you so much for your response. It was a show -stopper for our migration effort.

Translate