Expand my Community achievements bar.

Submissions are now open for the 2026 Adobe Experience Maker Awards.

Flush page and re build cache in all dispatchers

Avatar

Level 3

Hi Team,

 

Can anyone please suggest a solution for the following scenario?

I need to flush the Dispatcher cache and regenerate it across all Dispatcher instances for a specific AEM page, without publishing or activating the page.
I'm looking for a solution that can be triggered directly from AEM, preferably using a scheduler that runs at a configurable interval.

Any guidance, sample code, or best practices to achieve this would be greatly appreciated.

 

Thanks in Advance.

Veera

5 Replies

Avatar

Level 10

hi @veerareddyc1015, you can force the behaviour into the dispatcher with a POST call

POST /dispatcher/invalidate.cache HTTP/1.1
CQ-Action: Activate
`Content-Type: text/plain
CQ-Handle: path-pattern
Content-Length: numchars in bodypage_path0

page_path1
...
page_pathn

as explained here.You can set up a scheduler for each publishing instance to trigger a POST call, ensuring that all dispatchers in the infrastructure will rebuild the cache. The scheduler must compute all the links for the website, similar to a sitemap, so that these links can be included in the body of the POST request.

 

Avatar

Level 3

Thank you for the response. I'm using AEM 6.5.22.0 and have configured it as shown below. The cached page is getting removed as expected upon activation, but it's not being re-cached. Could you please let me know if I'm missing something?

veerareddyc1015_0-1749833701197.png

 

Avatar

Level 10

Adjusting the replication agent is ineffective because it is essential for the post to function correctly. Specifically, the header "CQ-Handle" must include the deepest page (you can refer to this documentation for clarification) among those to be invalidated. If this condition is not met, the resource will not be re-cached.

 

Here is the code that works correctly:

CloseableHttpResponse invalidateAndRecache(String dispatcherUrl,
                                                                  Set<String> pagesToInvalidate, 
                                                                  String domain, 
                                                                  String cqHandlePath) throws IOException {
        HttpPost post = new HttpPost(dispatcherUrl);
        post.addHeader("CQ-Action", "Activate");
        post.addHeader("CQ-Handle", cqHandlePath);
        post.addHeader("Host", domain);
        post.addHeader("CQ-Action-Scope", "ResourceOnly");
        post.addHeader("Content-Type", "text/plain");
        String bodyString = StringUtils.join(pagesToInvalidate, "\n");
        StringEntity body = new StringEntity(bodyString);
        post.setEntity(body);

        CloseableHttpResponse execute = httpClientService.getConfiguredHttpClient().execute(post);
        return execute;
    }

@Component(service = HttpClientService.class, immediate = true)
public class HttpClientServiceImpl implements HttpClientService {

    private CloseableHttpClient httpClient;

    @Override
    public CloseableHttpClient getConfiguredHttpClient() {
        [...]
        return this.httpClient;
    }
}

 

 

Avatar

Level 4

if you are looking for auto flush based on scheduled frequencies, OSGI config can be helpful

1. Create OSGI config that gets reflected in Felix Server(/system/console) --> Configuration tab

DispatcherCacheRefresherConfig.java

import org.osgi.service.metatype.annotations.ObjectClassDefinition;
import org.osgi.service.metatype.annotations.AttributeDefinition;

@ObjectClassDefinition(name = "Dispatcher Cache Refresher Config")
public @interface DispatcherCacheRefresherConfig {

@AttributeDefinition(name = "Page Path", description = "Path of the page to flush and regenerate")
String pagePath();

@AttributeDefinition(name = "Dispatcher Flush URL", description = "URL used to flush the dispatcher cache")
String flushUrl();

@AttributeDefinition(name = "Cron Expression", description = "Cron expression for scheduler")
String schedulerExpression() default "0 0/30 * * * ?"; // every 30 min

@AttributeDefinition(name = "Enabled", description = "Enable or disable the job")
boolean enabled() default true;
}


2. Create a Scheduler to execute job based on the config parameters defined in above OSGI Conf

DispatcherCacheRefresher.java

import org.osgi.service.component.annotations.*;
import org.osgi.service.metatype.annotations.Designate;
import org.apache.sling.commons.scheduler.Scheduler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.HttpURLConnection;
import java.net.URL;

@component(service = Runnable.class, immediate = true)
@Designate(ocd = DispatcherCacheRefresherConfig.class)
public class DispatcherCacheRefresher implements Runnable {

private final Logger log = LoggerFactory.getLogger(this.getClass());

@reference
private Scheduler scheduler;

private DispatcherCacheRefresherConfig config;
private static final String osgiJob = "dispatcher-cache-refresher";

@activate
@MODIFIED
protected void activate(DispatcherCacheRefresherConfig config) {
this.config = config;

if (config.enabled()) {
try {
scheduler.remove(osgiJob);
scheduler.addJob(osgiJob, this, null, config.schedulerExpression(), true);
log.info("Dispatcher Cache Refresher job scheduled.");
} catch (Exception e) {
log.error("Error scheduling job", e);
}
}
}

@deactivate
protected void deactivate() {
scheduler.remove(osgiJob);
}

@Override
public void run() {
try {
flushDispatcherCache(config.flushUrl());
regeneratePage(config.pagePath());
} catch (Exception e) {
log.error("Error in dispatcher cache refresher job", e);
}
}

private void flushDispatcherCache(String flushUrl) throws Exception {
log.info("Flushing Dispatcher Cache at {}", flushUrl);
HttpURLConnection con = (HttpURLConnection) new URL(flushUrl).openConnection();
con.setRequestMethod("GET");
int responseCode = con.getResponseCode();
log.info("Flush response code: {}", responseCode);
}

private void regeneratePage(String pagePath) throws Exception {
String url = "http://localhost:4503" + pagePath + ".html"; // assuming publish or internal dispatcher
log.info("Regenerating page by requesting: {}", url);
HttpURLConnection con = (HttpURLConnection) new URL(url).openConnection();
con.setRequestMethod("GET");
int responseCode = con.getResponseCode();
log.info("Page regeneration response code: {}", responseCode);
}
}

Now, 

  • Deploy the OSGi service.

  • Configure the values in system/console/configmgr

  • Verify cache files are removed and regenerated under the dispatcher docroot(folder created in your webtop/mac/server

    Hope this gives info you are looking for.

    Thanks
    Kiran Buthpur

 

Avatar

Administrator

@veerareddyc1015 

Just checking in — were you able to resolve your issue?
We’d love to hear how things worked out. If the suggestions above helped, marking a response as correct can guide others with similar questions. And if you found another solution, feel free to share it — your insights could really benefit the community. Thanks again for being part of the conversation!



Kautuk Sahni