Expand my Community achievements bar.

send multiple paths in one dispatcher cache invalidate API

Avatar

Level 2


How to send page multiple paths to invalidate dispatcher cache in one request instead of loop?

import com.amazonaws.http.apache.request.impl.HttpGetWithBody;
import com.esa.service.CacheInvalidationConfig;
import com.esa.service.CacheInvalidationService;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.fluent.Form;
import org.apache.http.client.fluent.Request;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.Set;

@component(service = CacheInvalidationService.class, immediate=true)
public class CacheInvalidationServiceImpl implements CacheInvalidationService {

@reference
private CacheInvalidationConfig cacheInvalidationConfig;

private static final String DISPATCHER_URL_PATH_API = "/dispatcher/invalidate.cache";
private static final Logger LOG = LoggerFactory.getLogger(CacheInvalidationServiceImpl.class);

public void invalidateCache(Set<String> pagePaths) {
String [] dispatcherHost = cacheInvalidationConfig.getDispatcherURL();
for (String path : pagePaths) {
for (String dispatcherURL : dispatcherHost) {
String apiURL = dispatcherURL + DISPATCHER_URL_PATH_API;
Request request = Request.Get(apiURL);
request.setHeader("Host", "flush");
request.setHeader("CQ-Action", "Activate");
request.setHeader("CQ-Handle", path);
HttpResponse httpResponse = null;
try {
httpResponse = request.execute().returnResponse();
LOG.info("Prepared URL : {} ,CQ Handle : {}", apiURL, path);
if (null != httpResponse && null != httpResponse.getStatusLine()) {
final int statusCode = httpResponse.getStatusLine().getStatusCode();
LOG.info("Response Code for Cache Clear Request: {}", statusCode);
}
}
catch (Exception e) {
LOG.error("Dispatcher API Error : {}",e.getMessage(),e);
}
}
}
}

}

9 Replies

Avatar

Community Advisor

Hi @NehaMi 
You can pass multiple paths in request body , please check

https://experienceleague.adobe.com/en/docs/experience-manager-dispatcher/using/configuring/page-inva... 

 

Please check the recache part here, it may create load on publishers if there are too many URLs to invalidate



Arun Patidar

Avatar

Level 2

Hi @arunpatidar ,

I have tried to send multiple paths in request body with this code, but in dispatcher log , i can see only one entry for invalidate cache - 

Activation detected: action=Activate [/content/esa/hn/cphi]

 

package com.esa.service.impl;

import com.amazonaws.http.apache.request.impl.HttpGetWithBody;
import com.esa.service.CacheInvalidationConfig;
import com.esa.service.CacheInvalidationService;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.fluent.Form;
import org.apache.http.client.fluent.Request;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.util.EntityUtils;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.util.Set;

@Component(service = CacheInvalidationService.class, immediate=true)
public class CacheInvalidationServiceImpl implements CacheInvalidationService {

@Reference
private CacheInvalidationConfig cacheInvalidationConfig;

private static final String DISPATCHER_URL_PATH_API = "/dispatcher/invalidate.cache";
private static final Logger LOG = LoggerFactory.getLogger(CacheInvalidationServiceImpl.class);


public void invalidateCache(String path) {
String[] dispatcherHost = cacheInvalidationConfig.getDispatcherURL();
for (String dispatcherURL : dispatcherHost) {
String requestBody = "/content/esa/hn/pharmapack,/content/esa/hn/cphi";
String apiURL = dispatcherURL + DISPATCHER_URL_PATH_API;

try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
HttpPost httpPost = new HttpPost(apiURL);
httpPost.setHeader("Content-Type", "text/plain");

httpPost.setHeader("Host", "flush");
httpPost.setHeader("CQ-Action", "Activate");
httpPost.setHeader("CQ-Handle", path);
httpPost.setEntity(new StringEntity(requestBody));
try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
LOG.info("invalidateCacheNew :: Prepared URL : {} ,CQ Handle : {}", apiURL, path);
int statusCode = response.getStatusLine().getStatusCode();
LOG.info("invalidateCacheNew :: Response Code for Cache Clear Request: {}", statusCode);
}} catch (Exception e) {
LOG.error("invalidateCacheNew :: Dispatcher API Error : {}",e.getMessage(),e);
}
}
}

}

Avatar

Community Advisor

Hi @NehaMi 
You can try something like below

 

HttpPost post = new HttpPost(dispatcherHost);
        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);

where pagesToInvalidate is a arrayList type



Arun Patidar

Avatar

Level 2

Hi @arunpatidar ,

After implementing this approach, we receive a 200 response, but the cache is only cleared for the path specified in cq-handle.

http://localhost:4502/content/data/servlet/cacheValidation?paths=/content/test/hn/test-site1,/conten...

 

In this case, the cache is cleared only for /content/test/hn/test-site1 and not for /content/test/hn/test-site2.

 

Code 

@Override
protected void doGet(@NotNull SlingHttpServletRequest request, @NotNull SlingHttpServletResponse response) throws ServletException, IOException {
String paths = request.getParameter("paths");
String cqHandle = request.getParameter("cqHandle");
ArrayList<String> list = new ArrayList<>(Arrays.asList(paths.split(",")));
cacheInvalidationService.invalidateCacheTest(cqHandle,list);
}
public void invalidateCacheTest(String path, ArrayList<String> pagesToInvalidate) {
String[] dispatcherHost = cacheInvalidationConfig.getDispatcherURL();
for (String dispatcherURL : dispatcherHost) {

String requestBody = StringUtils.join(pagesToInvalidate, "\n");
String apiURL = dispatcherURL + DISPATCHER_URL_PATH_API;

try (CloseableHttpClient httpClient = HttpClients.createDefault()) {
HttpPost httpPost = new HttpPost(apiURL);
httpPost.setHeader("Content-Type", "text/plain");

httpPost.setHeader("Host", "flush");
httpPost.setHeader("CQ-Action", "Activate");
// httpPost.addHeader("CQ-Action-Scope", "ResourceOnly");
httpPost.setHeader("CQ-Handle", path);


httpPost.setEntity(new StringEntity(requestBody));

try (CloseableHttpResponse response = httpClient.execute(httpPost)) {
LOG.info("invalidateCacheNew :: Prepared URL : {} ,CQ Handle : {}, Request Body : {}", apiURL, path, requestBody);
int statusCode = response.getStatusLine().getStatusCode();
LOG.info("invalidateCacheNew :: Response Code for Cache Clear Request: {}", statusCode);
}} catch (Exception e) {
LOG.error("invalidateCacheNew :: Dispatcher API Error : {}",e.getMessage(),e);
}
}
}

Avatar

Community Advisor

Hi @NehaMi 
You may need to use path patterns for CQ-Handle header, try to use some kind of wild card or deepest path

I was checking same for other implementation and there 

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

 



Arun Patidar

Avatar

Employee Advisor

Why don't you use the replication API for this? 

Avatar

Level 2

Hi @Jörg_Hoh ,

The replication API is useful for publishing pages, but in our case, we don’t need to republish the page since there are no changes. It’s an asset content update that is already available on the publisher. We just need to clear the dispatcher cache from the author instance

Avatar

Employee Advisor

Well, for me that feels like a bandaid for a different problem...

Avatar

Administrator

@NehaMi Did you find the suggestions helpful? Please let us know if you require more information. Otherwise, please mark the answer as correct for posterity. If you've discovered a solution yourself, we would appreciate it if you could share it with the community. Thank you!



Kautuk Sahni