Hello,
I'm new to JIRA development and I'm following this article on implementing plugin caching: https://developer.atlassian.com/confdev/development-resources/confluence-developer-faq/how-do-i-cache-data-in-a-plugin
However, after installing my plugin and trying to test it, it does not behave as expected.
Each time I make a request to my plugin, it basically instantiates a new instance of my plugin. The constructor is called for every request I make, so a new CacheManager is created and each request does the expensive retrieval of data from the database. In other words, each request is like visiting my plugin for the very first time and effectively there is no caching because of this.
Why does my plugin not live beyond the scope of a single request? Is this perhaps a plugin scope configuration that I need to configure? I read the article about JIRA plugin lifecycle: https://developer.atlassian.com/jiradev/jira-platform/building-jira-add-ons/jira-plugins2-overview/jira-plugin-lifecycle#JIRAPluginLifecycle-Componentinitialisation and also read articles about "JIRA plugin scope" but they're not talking about plugin scope as it relates to development.
Thanks in advance!
Hello,
You need to inject CacheManager. In this case CacheManager always stays the same. Also you can make your class as a bean adding Named annotation to the class. It is difficult to say for sure what is wrong with your code because you did not provide it.
Hi Alexey,
Thanks for your help! I am injecting the CacheManager into my constructor and also I have just tried adding the "Named" annotation, however it still does not work. Here is a simplified version of my plugin code:
@Named("MyPlugin")
@Scanned
public class MyPlugin extends JiraWebActionSupport
{
private static final Logger log = LoggerFactory.getLogger(MyPlugin.class);
private MyDBService db;
@ComponentImport
private final PermissionManager permissionMgr;
@ComponentImport
private final CacheManager cachMgr;
private final Cache myCache;
private List<MyField> myFields;
@Inject
public MyPlugin(MyDBService mydb, PermissionManager permissionMgr, CacheManager cachMgr) {
this.db = mydb;
this.permissionMgr = permissionMgr;
this.cachMgr = cachMgr;
myCache = cachMgr.getCache(MyPlugin.class.getName() + "-MyCache.cache",
new MyDataLoader(),
new CacheSettingsBuilder().expireAfterAccess(50, TimeUnit.MINUTES).build());
log.debug("MyPlugin Constructor called!");
}
@Override
public String execute() throws Exception {
myFields = (List<MyField>) myCache.get("myData")
return super.execute();
}
private class MyDataLoader implements CacheLoader<String,List<MyField>> {
public List<MyField> load(@Nonnull String s) {
if(s.equals("myData")) {
log.debug("retrieved data from db!");
return db.getAllData();
}
return null;
}
}
}
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You put @Named annotation and made atlas-clean and then atlas-run? And then every time you enter your webwork item you fall into the constructor? If so, make you private MyDataLoader class as a bean and pass it to the constructor.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Also I found this article
The point is that
myCache = cachMgr.getCache(MyPlugin.class.getName() + "-MyCache.cache",
new MyDataLoader(),
new CacheSettingsBuilder().expireAfterAccess(50, TimeUnit.MINUTES)
.build());
must be called once. So I would make a bean and make the myCache as a property of the bean. Then I would inject it into the constructor of your Webwork.
But That would be true only if the constructor of your Webwork is called everytime you call the webwork. I need to check it. But I can not check it right now. But I ll try to check it tomorrow.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Hi Alexey,
Thank you so much for your help. I did some quick testing and it seems your suggestion will work:
- create a separate dedicated 'cache bean' with the cache objects as properties (and instantiate the cache properties in this bean's constructor -- which will only be called once)
- inject this dedicated 'cache bean' into my plugin bean's constructor
Even though my plugin bean constructor is called once per request (intended by design or not), the 'cache bean' constructor will only be invoked once when the bean is initially injected (so the cache objects stay the same and the cached data are reused).
Thanks again, Alexey!
Best regards,
victor
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
Oh btw, re: your question about atlas-clean atlas-run..
I was just making my changes, then doing: atlas-mvn package
Then I'd uninstall and reinstall the newly compiled .jar into the JIRA instance and test it.
(But I also tried doing atlas-clean and then atlas-mvn package and it didn't fix my problem.. it seems since my plugin constructor is called many times, the only solution is to refactor out the instantiation of the cache objects into a separate bean and inject back into my plugin)
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.
You must be a registered user to add a comment. If you've already registered, sign in. Otherwise, register and sign in.