AMS to AEMaaCS Migration - Performing certain job on Publish tier | Community
Skip to main content
Level 2
February 12, 2026
Solved

AMS to AEMaaCS Migration - Performing certain job on Publish tier

  • February 12, 2026
  • 1 reply
  • 25 views

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.

Best answer by giuseppebaglio

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.

1 reply

giuseppebaglio
giuseppebaglioAccepted solution
Level 10
February 13, 2026

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.

Level 2
February 13, 2026

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.