I am using the Job DSL Jenkins plugin, and I have got a problem regarding the trigger. It is deprecated and when I update the code, then the deprecation warning is still shown.
Here the code before:
protected def job
void nightly(String schedule='H 0 * * *') {
job.triggers {
cron(schedule)
}
}
Then the update according to: https://github.com/jenkinsci/job-dsl-plugin/wiki/Migration
void nightly(String schedule='H 0 * * *') {
properties {
pipelineTriggers {
job.triggers {
cron(schedule)
}
}
}
}
There is still a warning: Warning: (JobBuilder.groovy, line 100) triggers is deprecated
What am I doing wrong? Is the properties keyword wrong or should it be job.properties?
thanks in advance
job basically represents project block of a job XML configuration file and its methods are converted to nested XML elements.
Your initial code
void nightly(String schedule = 'H 0 * * *') {
job.triggers {
cron(schedule)
}
}
renders this part:
<triggers>
<hudson.triggers.TimerTrigger>
<spec>H 4 * * *</spec>
</hudson.triggers.TimerTrigger>
</triggers>
Your updated code does effectively the same thing, because you are calling triggers method of job exactly like before the update. Another problem is that cron method specification for pipelineTriggers is different, so the correct code is:
void nightly(String schedule = 'H 0 * * *') {
job.properties {
pipelineTriggers {
triggers {
cron {
spec(schedule)
}
}
}
}
}
You can view available Jenkins DSL methods at https://your.jenkins.domain/plugin/job-dsl/api-viewer/index.html
Related
I created a Laravel Job with 3 tries and timeout after 10 minutes. I am using Horizon.
I can handle the failure after 3 tries using the method failed, but how can I handle the timeout event each 3 tries of this job ?
Used for logging and feedback, I want my user to be notified when the first or second try fails and it will be retried later.
class MyJob implements ShouldQueue
{
public $tries = 3;
public $timeout = 600;
// [...]
public function failed(Throwable $exception)
{
// The failure of the 3 tries.
}
// Any method for catching each timeouts ?
}
You may define the $failOnTimeout property on the job class
/**
* Indicate if the job should be marked as failed on timeout.
*
* #var bool
*/
public $failOnTimeout = true;
https://laravel.com/docs/9.x/queues#failing-on-timeout
I dont think there is a method for that,
But you can do something like catch the Error thrown if the job fails and verify that its from timeout exception which I believe would throw the exception handler Symfony\Component\Process\Exception\ProcessTimedOutException.
Something like;
public function handle() {
try {
// run job
} catch (\Throwable $exception) {
// manually fail it if attempt is more than twice
if ($this->attempts() > 2)
$this->fail($exception);
// Check if the error it timeout related
if ( $exception instanceof \Symfony\Component\Process\Exception\ProcessTimedOutException ) {
// Whatever you want to do when it fails due to timeout
}
// release the job back to queue after 5 seconds
$this->release(5);
return;
}
}
Just try running a job and make sure it fails because of timeout, to verify the actual timeout class exception
Ok I found the solution.
TLDR;
Put a pcntl_signal at the beginning of your your job handle() and then you can do something like call a onTimeout() method :
public function handle()
{
pcntl_signal(SIGALRM, function () {
$this->onTimeout();
exit;
});
// [...]
}
public function onTimeout()
{
// This method will be called each
}
The story behind :
The Queue documentation says : The pcntl PHP extension must be installed in order to specify job timeouts.
So, digging into the pcntl PHP documentation I found interesting pcntl_* functions. And a call of pcntl_signal into Illuminate/Queue/Worker.php l221.
It looks that if we register a method using pcntl_signal it replace the previous handler. I tried to load the Laravel one using pcntl_signal_get_handler but I can't manage to call it. So the workaroud is to call exit; so Laravel will consider the process as lost and mark it as timeout (?). There is the 3 tries, the retry_after is respected, and at the last try the job fails ... It may be cleaner to keep the original handler, but as it work well on my case so I will stop investigate.
I have implemented a scheduler with shedlock in my current spring project as follows:
#Scheduled(cron = "0 0/1 * * * *")
#SchedulerLock(name = "syncData",
lockAtMostFor = "${shedlock.myScheduler.lockAtMostFor}",
lockAtLeastFor = "${shedlock.myScheduler.lockAtLeastFor}")
public void syncSAData() {
//To assert that the lock is held
LockAssert.assertLocked();
...
}
Now I would like to write unit test for this function. Here the problem I am facing is: I am unable to mock first statement: LockAssert.assertLocked().
This should do the trick LockAssert.TestHelper.makeAllAssertsPass(true);
Just add it at the beginning of the test method.
Docs: https://github.com/lukas-krecan/ShedLock#lock-assert
So, while this is quite a kotlin-dsl for gradle specific issue, I think it overall applies to the kotlin language itself, so I am not going to use that tag.
In the gradle API, the class Action<T> is defined as:
#HasImplicitReceiver
public interface Action<T> {
/**
* Performs this action against the given object.
*
* #param t The object to perform the action on.
*/
void execute(T t);
}
So ideally, this should work in kotlin (because it is a class with a SAM):
val x : Action<String> = {
println(">> ${it.trim(0)}")
Unit
}
But I get the following two errors:
Unresolved reference it
Expected Action<String> but found () -> Unit
Fwiw, even Action<String> = { input: String -> ... } doesn't work.
Now here's the really intriguing part. If I do the following in IntelliJ (which btw, works):
object : Action<String> {
override fun execute(t: String?) {
...
}
}
IntelliJ pops the suggestion Convert to lambda, which when I do, I get:
val x = Action<String> {
}
which is better, but it is still unresolved. Specifying it now:
val x = Action<String> { input -> ... }
gives the following errors Could not infer type for input and Expected no parameters. Can someone help me with what is going on?
This is because the Action class in gradle is annotated with HasImplicitReceiver. From the documentation:
Marks a SAM interface as a target for lambda expressions / closures where the single parameter is passed as the implicit receiver of the invocation (this in Kotlin, delegate in Groovy) as if the lambda expression was an extension method of the parameter type.
(emphasis mine)
So, the following compiles just fine:
val x = Action<String> {
println(">> ${this.trim()}")
}
You could even just write ${trim()} and omit the this in front of it.
You need reference the function with class name, like:
val x: Action<String> = Action { println(it) }
Let's say I have some gradle task named:
:ProjectName:SubProjectName1:SubProjectName2:copyFiles
that I want to ignore. and I want to run the build task without having that run.
To be clear, I don't want to ignore all copyFiles, just :ProjectName:SubProjectName1:SubProjectName2:copyFiles.
Do I just do ./gradle -x :ProjectName:SubProjectName1:SubProjectName2:copyFiles build ?
Can it use wildcards? I.e. ./gradle -x :ProjectName:SubProjectName1:SubProjectName2:* build ?
Where can I find documentation that describes what formats are acceptable for this -x parameter?
Github code is the best help here
class StartParameter
/**
* Returns the names of the tasks to be excluded from this build. When empty, no tasks are excluded from the build.
*
* #return The names of the excluded tasks. Returns an empty set if there are no such tasks.
*/
public Set<String> getExcludedTaskNames() {
return excludedTaskNames;
}
class ExcludedTaskFilteringBuildConfigurationAction
public void configure(BuildExecutionContext context) {
GradleInternal gradle = context.getGradle();
Set<String> excludedTaskNames = gradle.getStartParameter().getExcludedTaskNames();
if (!excludedTaskNames.isEmpty()) {
final Set<Spec<Task>> filters = new HashSet<Spec<Task>>();
for (String taskName : excludedTaskNames) {
filters.add(taskSelector.getFilter(taskName));
}
gradle.getTaskGraph().useFilter(Specs.intersect(filters));
}
context.proceed();
}
As you can see, wildcards are not supported, -x refers to task names.
I received the following error:
Call to undefined method CI_Loader::plugin() in C:\wamp\www\Code\application\libraries\DX_Auth.php on line 1233
on this code:
function captcha()
{
$this->ci->load->helper('url');
$this->ci->load->plugin('dx_captcha');
$captcha_dir = trim($this->ci->config->item('DX_captcha_path'), './');
Make sure you have moved any array values in application/config/autoload.php from $autoload[‘plugins’] to $autoload[‘helpers’] or you will notice stuff break.
This is the reference
Which version of CI are you using? Plugins has been removed since the 2.x and replaced with helper.
Try to use reCaptcha instead, it has a good library.
You're trying to load a plugin and plugins are not supported, if I remember it right since CI version 2. If that's the case (which seems to be) you need to convert your plugins into helpers.
I think you are trying to use an old version of DX_Auth on new version of CodeIgniter. Current version of DX_Auth is compatible with CI 2.x and is available on github.
A simple way to solve this problem is that you just put this code in your loader.php. The plugin its works. Go to System->Core->Loader.php.
/**
* Load Plugin
*
* This function loads the specified plugin.
*
* #access public
* #param array
* #return void
*/
function plugin($plugins = array())
{
if ( ! is_array($plugins))
{
$plugins = array($plugins);
}
foreach ($plugins as $plugin)
{
$plugin = strtolower(str_replace(EXT, '', str_replace('_pi', '', $plugin)).'_pi');
if (isset($this->_ci_plugins[$plugin]))
{
continue;
}
if (file_exists(APPPATH.'plugins/'.$plugin.EXT))
{
include_once(APPPATH.'plugins/'.$plugin.EXT);
}
else
{
if (file_exists(BASEPATH.'plugins/'.$plugin.EXT))
{
include_once(BASEPATH.'plugins/'.$plugin.EXT);
}
else
{
show_error('Unable to load the requested file: plugins/'.$plugin.EXT);
}
}
$this->_ci_plugins[$plugin] = TRUE;
log_message('debug', 'Plugin loaded: '.$plugin);
}
}
// --------------------------------------------------------------------
/**
* Load Plugins
*
* This is simply an alias to the above function in case the
* user has written the plural form of this function.
*
* #access public
* #param array
* #return void
*/
function plugins($plugins = array())
{
$this->plugin($plugins);
}