Expand my Community achievements bar.

SOLVED

Modifying content fragments in Java code sometimes updates the GraphQL indexes and sometimes doesn't

Avatar

Level 4

The team I'm on is running into a strange issue when editing content fragments in Java. A common pattern we use based on years of working with AEM is to adapt a resource as a ModifiableValueMap in Java code and then edit one of the values of that ModifiableValueMap, commit the resourceResolver, thus saving the change. When we perform this action against content fragments the saved property has always been searchable in GraphQL, so we assumed this pattern was fine.

Recently we encountered a bug when performing content fragments in an implementation of the replication PreProcessor. Basically as a content fragment was published we used the PreProcessor hook to add a new field and then continue with publishing the fragment. The problem is that if we use the same ModifiableValueMap to perform the update, this new value isn't indexed. I understand that we should be using the Content Fragment API. It was being used initially and the value was being indexed. We'll go back to using the Content Fragment API, especially after encouragement from this presentation. https://adapt.to/2023/schedule/optimising-graphql-delivery-in-aem

What I'm wondering is this. Why does the data get indexed properly when using the ModifiableValueMap (essentially using the Sling API) and in other contexts the property isn't indexed? I'm wondering if anyone else has encountered this and can explain what the difference might be so that we can make sure to update our Java code accordingly. 

1 Accepted Solution

Avatar

Correct answer by
Level 6

Correct Preston. Your above presentation link was very helpful. I just, first time watched it, and understood I was also not doing per presentation. So I was NOT using the ContentFragment API. Was updating fragment master node directly with Sling. And my queries are path-based. Not list, searching by properties. So yeah, understood my points are not going to help this question. 

 

I ll also refactor to use ContentFragment API, build list query and see if I could reproduce your specific problem. Thanks for ignoring :). 

View solution in original post

4 Replies

Avatar

Level 6

Hi @Preston , can you please clarify,

  1. Is this CF publish inside some job that is bulk publishing multiple fragments, and you run into race conditions? 
  2. The updated field shows on author, but when run the graphql query from publisher, you dont find the data?  

I have a daily job in production, updating CF from external sources, and gets graphql queried by FE. Some of my experiences was 

  1. After you edit the ModifiableValueMap, always make sure to resolver.commit(); But not just simple commit. Do as 
try {
if (Objects.nonNull(resolver) && resolver.isLive() && resolver.hasChanges()) {
resolver.commit();
resolver.refresh();
}
} catch (PersistenceException e) {
LOG.error("Unable to commit the additions/changes. {}", e.getMessage());
}
  1. Issue I faced was, same resource (CF) was getting updated multiple times, and commitResolver fails saying resource already committed. I had to check resolver.hasChanges(), to ensure only dirty resolvers were getting committed
  2. If possible try to split the content updation and publishing activities separate. I too ran into a race condition, before resolver was getting committed, the resource lands into distribution queue. I had to split the tasks and run replication separated from updation.
  3. Third main issue, graphql queries are PERSISTED at publisher and cached at dispatcher. Regardless of cache-control, AEM default design is persistedQueries to promote performance. To get around, I add a datetimestamp to queryparam, so FE passes unique timestamp when if wants to bust cache. 

 

But if your issue is only inside author, worth to check if resource was really updated, by checking crxde with graphiQL output. For me always crxde properties matched with graphiQL query response. 

 

 

 

Avatar

Level 4

We see the issue solely on author as well. So working locally I will see the correct, updated field in jcr:content/data/master, but not in jcr:content/indexedData/master if I'm using the Sling API to update the fragment. This code is running in an implementation of the PreProcessor interface, so there's potentially a race condition. Maybe it's impossible to use the Sling API to update a fragment successfully inside this hook. Possibly. 

We are calling "resolver.commit()". I'll test "resolver.refresh()". None of the rest of your post applies to our case. We're seeing this completely on the author. Those are good questions, though, especially for the sake of completeness if anyone else has a similar issue. 

EDIT: Calling refresh didn't make a difference. 

Avatar

Correct answer by
Level 6

Correct Preston. Your above presentation link was very helpful. I just, first time watched it, and understood I was also not doing per presentation. So I was NOT using the ContentFragment API. Was updating fragment master node directly with Sling. And my queries are path-based. Not list, searching by properties. So yeah, understood my points are not going to help this question. 

 

I ll also refactor to use ContentFragment API, build list query and see if I could reproduce your specific problem. Thanks for ignoring :). 

Avatar

Level 4

Thanks. To be clear, this works great for me with the Content Fragment API.