For one of our applications we have a different Tasks that we would like to happen on a scheduled basis. However we don't want to bother with quartz for several different reasons.
In grails, how do we go about scheduling a task that can run on a regular basis?
After researching for quite some time we came to this conclusion:
Within the Groovy Source Packages we created an interface
interface Task{
void executeTask()
}
Next we created our Task:
class SayHelloTask implements Task{
void executeTask(){
println "Hello"
}
}
Within the resources.groovy file we added the following:
import package.SayHelloTask
beans = {
sayHelloTask(SayHelloTask){
}
xmlns task: "http://www.springframework.org/schema/task"
task.'scheduled-tasks'{
task.scheduled(ref:'retryEmailTask', method: 'executeTask', cron: '0-59 * * * * *')
}
}
We went with this solution because it cut the overhead of Quartz. It matches how we do things in our Java projects.
I prefer using the annotations on my services when dealing with Spring based scheduled tasks.
grails-app/conf/spring/resrouces.groovy
beans {
xmlns task: "http://www.springframework.org/schema/task"
task.'annotation-driven'('proxy-target-class': true)
}
Then on my service:
class MyService {
#Scheduled(cron="*/5 * * * * MON-FRI")
void doSomething() {
...
}
}
Regardless of how you do this, be cautious about your Hibernate session scope. Good luck!
For the records, as of Grails 3.2.10 this can be achieved neatly by using annotations the following way.
Create an ordinary Grails service:
class ScheduledService {
boolean lazyInit = false // <--- this is important
#Scheduled(fixedRate = 20000L)
def myBusinessMethodForTheJob() {
log.info 'Executing scheduled job...'
}
}
Enable scheduling in the application:
#EnableScheduling
class Application extends GrailsAutoConfiguration {
static void main(String[] args) {
GrailsApp.run(Application, args)
}
}
Done.
Another option is the Timer and TimerTask classes provided by the JDK. You can run this example in the Groovy console to see it in action
def task = new TimerTask() {
void run() {
println "task running at ${new Date()}"
}
}
def firstExecutionDelay = 1000
def delayBetweenExecutions = 2000
new Timer(true).schedule(task, firstExecutionDelay, delayBetweenExecutions)
Related
This question is a follow on after such a great answer Is there a way to upload jars for a dataflow job so we don't have to serialize everything?
This made me realize 'ok, what I want is injection with no serialization so that I can mock and test'.
Our current method requires our apis/mocks to be serialiable BUT THEN, I have to put static fields in the mock because it gets serialized and deserialized creating a new instance that dataflow uses.
My colleague pointed out that perhaps this needs to be a sink and that is treated differently? <- We may try that later and update but we are not sure right now.
My desire is from the top to replace the apis with mocks during testing. Does someone have an example for this?
Here is our bootstrap code that does not know if it is in production or inside a feature test. We test end to end results with no apache beam imports in our tests meaning we swap to any tech if we want to pivot and keep all our tests. Not only that, we catch way more integration bugs and can refactor without rewriting tests since the contracts we test are customer ones we can't easily change.
public class App {
private Pipeline pipeline;
private RosterFileTransform transform;
#Inject
public App(Pipeline pipeline, RosterFileTransform transform) {
this.pipeline = pipeline;
this.transform = transform;
}
public void start() {
pipeline.apply(transform);
pipeline.run();
}
}
Notice that everything we do is Guice Injection based so the Pipeline may be direct runner or not. I may need to modify this class to pass things through :( but anything that works for now would be great.
The function I am trying to get our api(and mock and impl to) with no serialization is thus
private class ValidRecordPublisher extends DoFn<Validated<PractitionerDataRecord>, String> {
#ProcessElement
public void processElement(#Element Validated<PractitionerDataRecord>element) {
microServiceApi.writeRecord(element.getValue);
}
}
I am not sure how to pass in microServiceApi in a way that avoid serialization. I would be ok with delayed creation as well after deserialization using guice Provider provider; with provider.get() if there is a solution there too.
Solved in such a way that mocks no longer need static or serialization anymore by one since glass bridging the world of dataflow(in prod and in test) like so
NOTE: There is additional magic-ness we have in our company that passes through headers from service to service and through dataflow and that is some of it in there which you can ignore(ie. the RouterRequest request = Current.request();). so for anyone else, they will have to pass in projectId into getInstance each time.
public abstract class DataflowClientFactory implements Serializable {
private static final Logger log = LoggerFactory.getLogger(DataflowClientFactory.class);
public static final String PROJECT_KEY = "projectKey";
private transient static Injector injector;
private transient static Module overrides;
private static int counter = 0;
public DataflowClientFactory() {
counter++;
log.info("creating again(usually due to deserialization). counter="+counter);
}
public static void injectOverrides(Module dfOverrides) {
overrides = dfOverrides;
}
private synchronized void initialize(String project) {
if(injector != null)
return;
/********************************************
* The hardest part is this piece since this is specific to each Dataflow
* so each project subclasses DataflowClientFactory
* This solution is the best ONLY in the fact of time crunch and it works
* decently for end to end testing without developers needing fancy
* wrappers around mocks anymore.
***/
Module module = loadProjectModule();
Module modules = Modules.combine(module, new OrderlyDataflowModule(project));
if(overrides != null) {
modules = Modules.override(modules).with(overrides);
}
injector = Guice.createInjector(modules);
}
protected abstract Module loadProjectModule();
public <T> T getInstance(Class<T> clazz) {
if(!Current.isContextSet()) {
throw new IllegalStateException("Someone on the stack is extending DoFn instead of OrderlyDoFn so you need to fix that first");
}
RouterRequest request = Current.request();
String project = (String)request.requestState.get(PROJECT_KEY);
initialize(project);
return injector.getInstance(clazz);
}
}
I suppose this may not be what you're looking for, but your use case makes me think of using factory objects. They may depend on the pipeline options that you pass (i.e. your PipelineOptions object), or on some other configuration object.
Perhaps something like this:
class MicroserviceApiClientFactory implements Serializable {
MicroserviceApiClientFactory(PipelineOptions options) {
this.options = options;
}
public static MicroserviceApiClient getClient() {
MyPipelineOptions specialOpts = options.as(MySpecialOptions.class);
if (specialOpts.getMockMicroserviceApi()) {
return new MockedMicroserviceApiClient(...); // Or whatever
} else {
return new MicroserviceApiClient(specialOpts.getMicroserviceEndpoint()); // Or whatever parameters it needs
}
}
}
And for your DoFns and any other execution-time objects that need it, you would pass the factory:
private class ValidRecordPublisher extends DoFn<Validated<PractitionerDataRecord>, String> {
ValidRecordPublisher(MicroserviceApiClientFactory msFactory) {
this.msFactory = msFactory;
}
#ProcessElement
public void processElement(#Element Validated<PractitionerDataRecord>element) {
if (microServiceapi == null) microServiceApi = msFactory.getClient();
microServiceApi.writeRecord(element.getValue);
}
}
This should allow you to encapsulate the mocking functionality into a single class that lazily creates your mock or your client at pipeline execution time.
Let me know if this matches what you want somewhat, or if we should try to iterate further.
I have no experience with Guice, so I don't know if Guice configurations can easily pass the boundary between pipeline construction and pipeline execution (serialization / submittin JARs / etc).
Should this be a sink? Maybe, if you have an external service, and you're writing to it, you can write a PTransform that takes care of it - but the question of how you inject various dependencies will remain.
I'm using grails jms-1.3plugin and I have the problem, that my jms listener Service starts consuming messages from activeMQ before the application is fully up and running. This results in an error when I try to write some messages to the DB.
So my question is, how can I manage to start consuming from a queue manually. So that I can set autoStartup to false.
here is my example grails code:
ConsumerService.groovy
package jmsstartstop
import grails.plugin.jms.Queue
class ConsumerService {
static exposes = ["jms"]
#Queue(name="liesMich")
def receiveMessage(String msg) {
log.info("Received Message:" + msg)
}
}
resources.groovy
import org.apache.activemq.ActiveMQConnectionFactory
import org.springframework.jms.connection.SingleConnectionFactory
beans = {
jmsConnectionFactory(SingleConnectionFactory) {
targetConnectionFactory = { ActiveMQConnectionFactory cf ->
brokerURL = grailsApplication.config.jms.brokerURL
}
}
}
Config.groovy
jms{
brokerURL='tcp://localhost:61616'
containers {
standard {
autoStartup = false
}
}
}
What I'm looking for is something like jmsConnectionFactory.getTargetConnectionFactory().start() that can be called in Bootstrap.groovy or maybe in a controller manually. But unfortunately this start method does not exist in the TargetConnectionFactory.
Is there a way to do it, or any other suggestions?
Bootstrap.groovy (which is not working)
class BootStrap {
def jmsConnectionFactory
def init = { servletContext ->
jmsConnectionFactory.??WHATEVER??.start()
}
def destroy = {
}
}
The issue is that the plugin starts processing messages before the Datasource plugin (part of Grails) has finished it's own startup.
The good news is that this appears to be fixed in the latest SNAPSHOT version of the plugin.
To use the SNAPSHOT change your plugin as such: :jms:1.3-SNAPSHOT in your BuildConfig.groovy
What worked for me is to MANUALLY start the JMSListener services on Bootstrap file:
e.g.
In listener.groovy:
class ClientListenerService {
boolean transactional = true
static exposes = ["jms"]
static destination = "com.moviesxd.api.domain.Client_QUEUE"
static isTopic = false
static container = "manualStart"
In bootstrap.groovy:
def clientRequestListenerJmsListenerContainer
...
clientRequestListenerJmsListenerContainer.start()
This solves the problem.
This line in TopLevelTransaction (neo4j-kernel-2.1.2) throws a NullPointerException every time I call next() on an iterator obtained via GraphRepository#findAll():
protected void markAsRollbackOnly()
{
try
{
transactionManager.getTransaction().setRollbackOnly(); // NPE here
}
catch ( Exception e )
{
throw new TransactionFailureException(
"Failed to mark transaction as rollback only.", e );
}
}
I found some threads about similar crashes with slightly different stack traces. The accepted solution on this question is to use "proxy" transaction management, but that seems like a band-aid solution. This question also mentions "proxy" transaction management and suggests that there might be something wrong with the #Transactional annotation when using AspectJ.
Is this legitimately a bug, or have I just set up my project incorrectly? My code is essentially the same as in my standalone hello world, with a slightly more complex main class:
#Component
public class Test2 {
#Autowired
FooRepository repo;
public static void main(String[] args) {
AbstractApplicationContext context = new AnnotationConfigApplicationContext("test2");
Test2 test2 = context.getBean(Test2.class);
test2.doStuff();
}
public void doStuff() {
createFoo();
printFoos();
}
#Transactional
public Foo createFoo() {
Foo foo = new Foo();
foo.setName("Derp" + System.currentTimeMillis());
repo.save(foo);
System.out.println("saved " + foo.toString());
return foo;
}
#Transactional
public void printFoos() {
Iterable<Foo> foos = repo.findAll();
System.out.println("findAll() returned instance of " + foos.getClass().getName());
Iterator<Foo> iter = foos.iterator();
System.out.println("iterator is instance of " + iter.getClass().getName());
if(iter.hasNext()) {
iter.next(); // CRASHES HERE
}
}
}
I can post my POM if needed.
I didn't find a bug. Two or three things are required to make this work, depending on whether you want to use proxy or AspectJ transaction management.
First, transaction management must be enabled. Since I'm using annotation-based configuration, I did this by annotating my #Configuration class with #EnableTransactionManagement. Contrary to the docs, the default mode now seems to be AdviceMode.ASPECTJ, not AdviceMode.PROXY.
Next, you need to ensure that the Iterator is used within a transaction. In my example, if I use AdviceMode.PROXY the entire bean containing the #Autowired repository has to be annotated #Transactional. If I use AdviceMode.ASPECTJ I can annotate just the method. This is because the call to the method using the iterator is a self-call from within the bean, and proxy transaction management cannot intercept and manage internal calls.
Finally, if you're using AdviceMode.ASPECTJ you must set up weaving as discussed here.
I have some (non-Grails-artifact) classes that access the service layer beans via passing around the grailsApplication object. However I'm having trouble unit testing the classes implemented in this way. Why doesn't the bean get registered in the main context?
#TestMixin(GrailsUnitTestMixin)
class ExampleTests {
void setUp() {}
void tearDown() {}
void testSomething() {
defineBeans {
myService(MyService)
}
assert grailsApplication.mainContext.getBean("myService") != null
}
}
The above code fails with:
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'myService' is defined
What I'm trying to do is access services from plain old Java classes via the grailsApplication. This works, but not in unit test environment. Should I do it differently?
class POJO {
MyService myService;
public POJO(GrailsApplication grailsApplication) {
myService = (MyService) grailsApplication.getMainContext().getBean("myService");
}
}
The answer is that in the GrailsUnitTestMixin the applicationContext that holds your beans is set as the parentContext in the grailsApplication
beans.registerBeans(applicationContext)
static void initGrailsApplication() {
...
//the setApplicationContext in DefaultGrailsApplication set's the parentContext
grailsApplication.applicationContext = applicationContext
}
So you can get your beans with:
defineBeans {
myService(MyService)
}
assert applicationContext.getBean("myService")
assert grailsApplication.parentContext.getBean("myService")
EDIT
Today I faced the same problem, and my solution is:
#Before
void setup() {
Holders.grailsApplication.mainContext.registerMockBean("myService", new MyService())
}
In my case (grails 2.4.4) the accepted solution didn't work but pointed me in the right direction, this line worked instead as the bean factory in the mainContext within my unit test was an OptimizedAutowireCapableBeanFactory
Holders.grailsApplication.mainContext.beanFactory.registerSingleton('myBean', new MyBeanClass())
I have spent some time with the same issue, in my case running grails 2.2.4 and having (in src/groovy):
import grails.util.Holders
class SomeClass {
transient myService = Holders.grailsApplication.mainContext.getBean 'myService'
.....
}
Which is a bit different to question author, but at least it will be useful for someone coming from search engine results
Nevertheless accepted answer did not work for me, so I came up with a bit different approach of mocking and registering service used in SomeClass.
import grails.util.Holders
.. other imports
#TestMixin(GrailsUnitTestMixin)
class SomeClassTests {
#Before
void setUp() {
Holders.grailsApplication = grailsApplication
defineBeans {
myService(MyServiceMock)
}
}
....
}
class MyServiceMock extends MyService {
// overriden methods here
}
I have a Grails service class that needs to do some cleanup when my Tomcat application server is shut down.
I don't see anything in the Grails docs about a service.stop() or destroy() method, or a way to implement any sort of application lifecycle listener.
What's the best way to do this?
Thanks!
You have a couple of options
Make your service implement org.springframework.beans.factory.DisposableBean
class MyService implements org.springframework.beans.factory.DisposableBean {
void destroy() throws Exception {
}
}
Or use an annotation
class MyService {
#PreDestroy
private void cleanUp() throws Exception {
}
}
IMO, the annotation option is preferable, because you can give your destructor method a more meaningful name than destroy and your classes public API doesn't expose the Spring dependency
The grails-app/conf/BootStrap.groovy can be used when the app starts and stops.
def init = {
println 'Hello World!'
}
def destroy = {
println 'Goodnight World!'
}
Note: When using development mode grails run-app on some OS's CTL+C will kill the JVM without the chance for a clean shutdown and the destroy closure may not get called. Also, if your JVM gets the kill -9 the closure wont run either.
I would try injecting the service into the Bootstrap and then calling the method from the destroy block, since the destroy block is executed when the application is terminated, something like this:
class BootStrap {
def myService
def init = {servletContext ->
}
def destroy = {
myService.cleanUp()
}
}
It's not quite the same as a service disposal method, but what I ended up doing is registering a Spring Bean with a shutdown method that gets called when the app is stopped.
First, create a bean class, like grails-app/utils/MyShutdownBean.groovy that looks like the following (there's nothing sacred about the class name or the method name, use whatever you want):
class MyShutdownBean {
public void cleanup() {
// Do cleanup stuff
}
}
Then register the bean in grails-app/conf/spring/resources.groovy like this:
beans = {
myShutdownHook(MyShutdownBean) { bean ->
bean.destroyMethod='cleanup'
}
}
If you want to only do the cleanup in production, you can register it like this instead:
beans = {
if (!grails.util.GrailsUtil.isDevelopmentEnv()) {
myShutdownHook(MyShutdownBean) { bean ->
bean.destroyMethod='cleanup'
}
}
}