How to get data with JAVA SDK in Scheduled services

Product/components used and version/fix level:

Cumulocity Production

Detailed explanation of the problem:

Hi, I am using java SDK to fetch data from my service. But I am not able to get any data. What I am doing is I have 1 method that I am calling from my main method since scheduler will run at a certain time, I am directly calling it from my main class.

    @Autowired
    CronJob cronJob;

    public static void main(String[] args) {
        SpringApplication.run(CronJobApplication.class, args);
    }

    @PostConstruct
    public void init() {
        TimeZone.setDefault(TimeZone.getTimeZone("UTC"));
        log.info("Current Time: " + CalibrationUtils.getCurrentTime());
        
        cronJob.sayHello();
    }
    @Autowired
    InventoryApi inventoryApi;

    @Autowired
    MeasurementApi measurementApi;

    @Autowired
    MicroserviceSubscriptionsService subscriptionsService;

    public void sayHello(){
        List<ManagedObjectRepresentation> morList = new ArrayList<>();
        subscriptionsService.runForEachTenant(() -> {
            inventoryApi.getManagedObjects().get().allPages().forEach(morList::add);
        });

        List<MeasurementCollection> meaList = new ArrayList<>();

        subscriptionsService.runForEachTenant(() -> {
            meaList.add(measurementApi.getMeasurements());
        });

        logger.info("Getting Managed Objects: "+morList);
        logger.info("Getting Measurements: "+meaList);
        logger.info("Managed Objects: "+inventoryApi.get(new GId("32409")));
    }

In console I am getting like:

Getting Managed Objects: [] 
Getting Measurements: []

and when I am running it without the subscription service I am getting error that tenant is not in scope.

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'cronJobApplication': Invocation of init method failed; nested exception is org.springframework.beans.factory.support.ScopeNotActiveException: Error creating bean with name 'scopedTarget.inventoryApi': Scope 'tenant' is not active for the current thread; consider defining a scoped proxy for this bean if you intend to refer to it from a singleton; nested exception is java.lang.IllegalStateException: Not within any context!
	at org.springframework.beans.factory.annotation.InitDestroyAnnotationBeanPostProcessor.postProcessBeforeInitialization(InitDestroyAnnotationBeanPostProcessor.java:160) ~[spring-beans-5.3.20.jar:5.3.20]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsBeforeInitialization(AbstractAutowireCapableBeanFactory.java:440) ~[spring-beans-5.3.20.jar:5.3.20]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1796) ~[spring-beans-5.3.20.jar:5.3.20]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:620) ~[spring-beans-5.3.20.jar:5.3.20]
	at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:542) ~[spring-beans-5.3.20.jar:5.3.20]
	at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:335) ~[spring-beans-5.3.20.jar:5.3.20]
	at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:234) ~[spring-beans-5.3.20.jar:5.3.20]
	at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:333) ~[spring-beans-5.3.20.jar:5.3.20]
	at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:208) ~[spring-beans-5.3.20.jar:5.3.20]
	at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:953) ~[spring-beans-5.3.20.jar:5.3.20]
	at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:918) ~[spring-context-5.3.20.jar:5.3.20]
	at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:583) ~[spring-context-5.3.20.jar:5.3.20]
	at org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.refresh(ServletWebServerApplicationContext.java:147) ~[spring-boot-2.7.0.jar:2.7.0]
	at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:734) ~[spring-boot-2.7.0.jar:2.7.0]
	at org.springframework.boot.SpringApplication.refreshContext(SpringApplication.java:408) ~[spring-boot-2.7.0.jar:2.7.0]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:308) ~[spring-boot-2.7.0.jar:2.7.0]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1306) ~[spring-boot-2.7.0.jar:2.7.0]
	at org.springframework.boot.SpringApplication.run(SpringApplication.java:1295) ~[spring-boot-2.7.0.jar:2.7.0]
	at com.CronJobApplication.main(CronJobApplication.java:24) ~[classes/:na]

I tried to follow this as well: https://github.com/SoftwareAG/cumulocity-microservice-templates/tree/main/multischeduler
But no luck, please help me with this. How can I get data in my scheduled service?

Thanks & Regards,
Samanyu

Hi @Sam123 ,

First of all: Could you elaborate a bit on your use case for this?
Do you want to run a task once the microservice starts or do you want to run it every e.g. X minutes/hours?

In general the template you mentioned is a very good start.
Especially this class: DeviceService which uses the “Scheduled annotation”:

Be aware of the following:

  • @Scheduled annotation requires the @EnableScheduling annotation
  • Depending on the “initialDelay” the first run of the scheduler might return no results if microservice initialisation is not completed yet (see below)

What are the challenges you face with the template?

I would suggest not using the @PostConstruct annotation, as the microservice subscription is time-sensitive especially after the startup of the microservice.
The initialisation takes some time until the microservice is fully ready, and doing request prior this could cause in getting empty responses.

Hi Kai,

So my use case is that I want to run my microservice every day at 1 AM and I want the time to be UTC. Thats why I am using @PostConstruct so that it will on start set the default time zone as UTC.

I have the @EnableScheduling on my main app. I used to run this app with rest endpoint, but my client suggested to use SDK that’s why I am converting it to use SDK.

I was just going to customize this template code in my use case, but I think this will only work once the microservice is subscribed and it will listen that event and do its stuff.

So, is there any way that without all this stuff I can directly use the inventory and measurement API and get data?

Best Regards,
Samanyu

Ok, understood.

But the @Scheduled annotation also allows to run based on a cron timer and you can also specify the timezone:

Example (not tested)

@Scheduled(cron = "0 1 * * * *", zone = "UTC")

With that you can easily fulfil your requirement without further modifications and less code :slight_smile:

I am not sure what you mean with “all this stuff”, but the solution above should be straight forward - based on the Cumulocity SDK.

Hi Kai,

I am running my Scheduled task with cron only but as I showed you above I am not getting any response from the SDK. In my console I am getting empty lists.

This is the response I am getting after calling the sdk methods.

Getting Managed Objects: [] 
Getting Measurements: []

Please go through my question again. By “all this stuff” I mean that the event listener is being used in the multischeduler project I dont want to use those. i just want to implement a simple service where I just use inventoryAPi to call my methods.

When I was using a controller in my other project and I was calling my method through my controller and sending request through postman, I was getting response but here I am not getting the response. Even I tried to run with
@Scheduled(* * * * * *)
this means that it will run every sec but still I didnt get any response from the sdk methods.

I have already populated my props file with bootstrap credentials got cumulocity maven dependencies.

Am I doing anything wrong or is there anything else to do to get the response from the methods?

Thanks & Regards,
Samanyu

Could you add some additional logging to the

subscriptionsService.runForEachTenant(() 

block? I suspect (as I think Kai does as well) that your scheduled job is run before the subscriptions become available. Can you then test running with a “Scheduled” annotation for 1min intervals?

1 Like

yes, you were right but if this is happening, I am going to run my application once a day at 1 am only so will the subscription be available when the job runs at 1 am?

Yes, they will be available.
It is just a short period (by default 30 seconds after microservice startup) until the subscription mechanism starts and makes the subscriptions available.
So in other words e.g. 1 minute after startup the subscriptions will be available and the @Scheduled block will work as expected.

1 Like

Oh, thats great Thank you for your help @Kai_Sieben and @Harald_Meyer

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.