ActivityPoller::__construct()   B
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 35
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 23
nc 2
nop 1
dl 0
loc 35
rs 8.8571
c 0
b 0
f 0
1
#!/usr/bin/php
2
3
<?php
4
5
/* Copyright (C) 2015, Sport Archive Inc. */
6
7
/* This program is free software; you can redistribute it and/or modify */
8
/* it under the terms of the GNU General Public License as published by */
9
/* the Free Software Foundation; either version 2 of the License, or */
10
/* (at your option) any later version. */
11
12
/* This program is distributed in the hope that it will be useful, */
13
/* but WITHOUT ANY WARRANTY; without even the implied warranty of */
14
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the */
15
/* GNU General Public License for more details. */
16
17
/* You should have received a copy of the GNU General Public License along */
18
/* with this program; if not, write to the Free Software Foundation, Inc., */
19
/* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */
20
21
/* Cloud Processing Engine, Copyright (C) 2015, Sport Archive Inc */
22
/* Cloud Processing Engine comes with ABSOLUTELY NO WARRANTY; */
23
/* This is free software, and you are welcome to redistribute it */
24
/* under certain conditions; */
25
26
/* June 29th 2015 */
27
/* Sport Archive Inc. */
28
/* [email protected] */
29
30
31
32
/**
33
 * The activity poller listen for "activity tasks" 
34
 * Stuff to do for this worker: compute, process, whatever.
35
 * The ActivityPoller can be configued to listen on a particular SWF TaskList (queue)
36
 * It will process tasks only coming in the TaskList
37
 */
38
39
require_once __DIR__ . "/../vendor/autoload.php";
40
41
use Aws\Swf\Exception;
0 ignored issues
show
Bug introduced by
This use statement conflicts with another class in this namespace, Exception.

Let’s assume that you have a directory layout like this:

.
|-- OtherDir
|   |-- Bar.php
|   `-- Foo.php
`-- SomeDir
    `-- Foo.php

and let’s assume the following content of Bar.php:

// Bar.php
namespace OtherDir;

use SomeDir\Foo; // This now conflicts the class OtherDir\Foo

If both files OtherDir/Foo.php and SomeDir/Foo.php are loaded in the same runtime, you will see a PHP error such as the following:

PHP Fatal error:  Cannot use SomeDir\Foo as Foo because the name is already in use in OtherDir/Foo.php

However, as OtherDir/Foo.php does not necessarily have to be loaded and the error is only triggered if it is loaded before OtherDir/Bar.php, this problem might go unnoticed for a while. In order to prevent this error from surfacing, you must import the namespace with a different alias:

// Bar.php
namespace OtherDir;

use SomeDir\Foo as SomeDirFoo; // There is no conflict anymore.
Loading history...
42
use SA\CpeSdk;
43
44
class ActivityPoller
45
{
46
    private $debug;
47
    private $cpeSwfHandler;
48
    private $cpeLogger;
49
    
50
    private $domain;
51
    private $taskList;
52
    private $activityName;
53
    private $activityVersion;
54
    private $activityHandler;
55
    private $knownActivities;
56
    
57
    const ACTIVITY_FAILED = "ACTIVITY_FAILED";
58
  
59
    public function __construct($config)
60
    {
61
        global $debug;
62
        global $cpeLogger;
63
        
64
        global $domain;
65
        global $taskList;
66
        global $activityName;
67
        global $activityVersion;
68
        
69
        $this->debug           = $debug;
70
        $this->cpeLogger       = $cpeLogger;
71
72
        // SWF related
73
        $this->domain          = $domain;
74
        $this->taskList        = $taskList;
75
        $this->activityName    = $activityName;
76
        $this->activityVersion = $activityVersion;
77
        $this->knownActivities = $config->{'activities'};
78
        
79
        // For creating SWF object 
80
        $this->cpeSwfHandler   = new CpeSdk\Swf\CpeSwfHandler($this->debug);
81
        
82
        // Check and load activities to handle
83
        if (!$this->register_activities()) {
84
            $msg = "No activity class registered! Check the logs (/var/tmp/logs/cpe/). Exiting ...\n";
85
            $cpeLogger->log_out(
86
                "FATAL", 
87
                basename(__FILE__),
88
                $msg
89
            );
90
            print $msg;
91
            exit(1);
92
        }
93
    }
94
    
95
    // We poll for new activities
96
    // Return true to keep polling even on failure
97
    // Return false will stop process !
98
    public function poll_for_activities()
99
    {
100
        // Poll from all the taskList registered for each activities 
101
        if ($this->debug)
102
            $this->cpeLogger->log_out("DEBUG", basename(__FILE__),
103
                "Polling activity taskList '" . $this->taskList  . "' ... ");
104
            
105
        try {
106
            // Call SWF and poll for incoming tasks
107
            $activityTask = $this->cpeSwfHandler->swf->pollForActivityTask([
108
                    "domain"   => $this->domain,
109
                    "taskList" => array("name" => $this->taskList)
110
                ]);
111
112
            // Handle and process the new activity task
113
            $this->process_activity_task($activityTask);
114
        } catch (CpeSdk\CpeException $e) {
0 ignored issues
show
Bug introduced by
The class SA\CpeSdk\CpeException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
115
            $this->cpeLogger->log_out("ERROR", basename(__FILE__),
116
                "Unable to poll activity tasks! " . $e->getMessage());
117
        }
118
        
119
        return true;
120
    }
121
122
    // Process the new task using one of the activity handler classes registered
123
    private function process_activity_task($activityTask)
124
    {
125
        // Get activityType and WorkflowExecution info
126
        if (!($activityType      = $activityTask->get("activityType")) ||
127
            !($workflowExecution = $activityTask->get("workflowExecution")))
128
            return false;
129
        
130
        $this->cpeLogger->log_out("INFO",
131
            basename(__FILE__),
132
            "Starting activity: name=" 
133
            . $activityType['name'] . ",version=" . $activityType['version'],
134
            $workflowExecution['workflowId']);
135
136
        // Has activity handler object been instantiated ?
137
        if (!isset($this->activityHandler)) 
138
        {
139
            $this->cpeLogger->log_out("ERROR", basename(__FILE__),
140
                "The activity handler class for this activity type is not instantiated !",
141
                $workflowExecution['workflowId']);
142
            
143
            return false;
144
        }
145
        
146
        $result = null;
147
        $reason = 0;
148
        $details = 0;
149
        try {
150
            // Check activity task
151
            $this->activityHandler->do_task_check($activityTask);
152
            // Perform input validation
153
            $this->activityHandler->do_input_validation();
154
155
            if ($this->debug)
156
                $this->cpeLogger->log_out("DEBUG", basename(__FILE__), 
157
                    "Activity input:\n" . print_r($this->activityHandler->input, true));
158
        
159
            // Run activity task
160
            $result = $this->activityHandler->do_activity($activityTask);
161
162
            if ($this->debug && $result)
163
                $this->cpeLogger->log_out("DEBUG", basename(__FILE__), 
164
                    "Activity output:\n" . print_r($result, true));
165
        
166
        } catch (CpeSdk\CpeException $e) {
0 ignored issues
show
Bug introduced by
The class SA\CpeSdk\CpeException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
167
            $reason  = $e->ref;
168
            $details = $e->getMessage();
169
        } catch (Exception $e) {
0 ignored issues
show
Bug introduced by
The class Aws\Swf\Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
170
            $reason  = self::ACTIVITY_FAILED;
171
            $details = $e->getMessage();
172
        } finally {
173
            if ($reason && $details)
174
            {
175
                // Activity has failed!
176
                // We send back to SWF the reason and details about the failure
177
                $this->activityHandler->activity_failed(
178
                    $activityTask, 
179
                    $reason, 
180
                    $details
181
                );
182
                return false;
183
            }
184
        }
185
    
186
        // Activity has completed!
187
        $this->activityHandler->activity_completed($activityTask, $result);
188
        return true;
189
    }
190
  
191
    // Register and instantiate activities handlers classes
192
    private function register_activities()
193
    {
194
        foreach ($this->knownActivities as $knownActivity)
195
        {
196
            if ($this->activityName == $knownActivity->{"name"} &&
197
                $this->activityVersion == $knownActivity->{"version"})
198
            {
199
                $activityToHandle = $knownActivity;
200
                
201
                if (!file_exists($activityToHandle->{"file"}))
202
                {
203
                    $this->cpeLogger->log_out("ERROR", basename(__FILE__),
204
                        "The code file '".$activityToHandle->{"file"}."' for activity: name=" 
205
                        . $activityToHandle->{"name"} . ",version=" 
206
                        . $activityToHandle->{"version"}." doesn't exists! Check if the file is accessible and if the path is correct in your config file.");
207
                    return false;
208
                }
209
                
210
                $this->cpeLogger->log_out("INFO", basename(__FILE__),
211
                    "Registering Activity: $this->activityName:$this->activityVersion");
212
        
213
                // Load the file implementing the activity
214
                require_once $activityToHandle->{"file"};
215
                
216
                // Instantiate the Activity class that will process Tasks
217
218
                if (!isset($this->cpeLogger) ||
219
                    !$this->cpeLogger)
220
                    print "EMPTY !!!\n";
221
222
                $params = [
223
                    "domain"  => $this->domain,
224
                    "name"    => $activityToHandle->{"name"},
225
                    "version" => $activityToHandle->{"version"}
226
                ];
227
                if (isset($activityToHandle->{"defaultTaskStartToCloseTimeout"}))
228
                    $params["defaultTaskStartToCloseTimeout"] =
229
                        $activityToHandle->{"defaultTaskStartToCloseTimeout"};
230
                if (isset($activityToHandle->{"defaultTaskHeartbeatTimeout"}))
231
                    $params["defaultTaskHeartbeatTimeout"] =
232
                        $activityToHandle->{"defaultTaskHeartbeatTimeout"};
233
                if (isset($activityToHandle->{"defaultTaskScheduleToStartTimeout"}))
234
                    $params["defaultTaskScheduleToStartTimeout"] =
235
                        $activityToHandle->{"defaultTaskScheduleToStartTimeout"};
236
                if (isset($activityToHandle->{"defaultTaskScheduleToCloseTimeout"}))
237
                    $params["defaultTaskScheduleToCloseTimeout"] =
238
                        $activityToHandle->{"defaultTaskScheduleToCloseTimeout"};
239
                
240
                $this->activityHandler = 
241
                    new $activityToHandle->{"class"}(
242
                        $params, 
243
                        $this->debug,
244
                        $this->cpeLogger
245
                    );
246
                
247
                $this->cpeLogger->log_out("INFO", basename(__FILE__),
248
                    "Activity handler registered: name=" 
249
                    . $activityToHandle->{"name"} . ",version=" 
250
                    . $activityToHandle->{"version"});
251
252
                return true;
253
            }
254
        }
255
        
256
        $this->cpeLogger->log_out("ERROR", basename(__FILE__),
257
            "No Activity handler was found for: name=" 
258
            . $this->activityName . ",version=" 
259
            . $this->activityVersion.". Check your config file and ensure your 'activity' name AND 'version' is there.");    
260
        return false;
261
    }
262
}
263
264
265
266
/*
267
 ***************************
268
 * POLLER START
269
 ***************************
270
*/
271
272
// Globals
273
$debug = false;
274
$cpeLogger;
275
276
// Usage
277
function usage($defaultConfigFile)
0 ignored issues
show
Best Practice introduced by
The function usage() has been defined more than once; this definition is ignored, only the first definition in client_example/ClientCommander.php (L110-123) is considered.

This check looks for functions that have already been defined in other files.

Some Codebases, like WordPress, make a practice of defining functions multiple times. This may lead to problems with the detection of function parameters and types. If you really need to do this, you can mark the duplicate definition with the @ignore annotation.

/**
 * @ignore
 */
function getUser() {

}

function getUser($id, $realm) {

}

See also the PhpDoc documentation for @ignore.

Loading history...
278
{
279
    echo("Usage: php ". basename(__FILE__) . " -D <domain> -A <activity_name> -V <activity_version> [-T <task_list>] [-h] [-d] [-c <config_file path>] [-l <log path>]\n");
280
    echo("-h: Print this help\n");
281
    echo("-d: Debug mode\n");
282
    echo("-c <config_file path>: Optional parameter to override the default configuration file: '$defaultConfigFile'.\n");
283
    echo("-l <log_path>: Location where logs will be dumped in (folder).\n");
284
    echo("-D <domain>: SWF domain your Workflow runs on.\n");
285
    echo("-A <activity_name>: Activity name this Poller can process.\n");
286
    echo("-V <activity_version>: Activity version this Poller can process.\n");
287
    echo("-T <task list>: Specify the Activity Task List this activity will listen to. An Activity Task list is the queue your Activity poller will listen to for new tasks. If not specified, it will listen to the default channel used by the Decider : 'activity_name-activity_version'.\n");
288
    exit(0);
289
}
290
291
// Check command line input parameters
292
function check_input_parameters(&$defaultConfigFile)
0 ignored issues
show
Best Practice introduced by
The function check_input_parameters() has been defined more than once; this definition is ignored, only the first definition in client_example/ClientCommander.php (L63-108) is considered.

This check looks for functions that have already been defined in other files.

Some Codebases, like WordPress, make a practice of defining functions multiple times. This may lead to problems with the detection of function parameters and types. If you really need to do this, you can mark the duplicate definition with the @ignore annotation.

/**
 * @ignore
 */
function getUser() {

}

function getUser($id, $realm) {

}

See also the PhpDoc documentation for @ignore.

Loading history...
293
{
294
    global $debug;
295
    global $cpeLogger;
296
297
    // Filling the globals with command input
298
    global $domain;
299
    global $taskList;
300
    global $activityName;
301
    global $activityVersion;
302
    
303
    // Handle input parameters
304
    if (!($options = getopt("D:T:A:V:c:l:hd")))
305
        usage($defaultConfigFile);
0 ignored issues
show
Unused Code introduced by
The call to usage() has too many arguments starting with $defaultConfigFile.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
306
    
307
    if (!count($options) || isset($options['h']))
308
        usage($defaultConfigFile);
0 ignored issues
show
Unused Code introduced by
The call to usage() has too many arguments starting with $defaultConfigFile.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
309
310
    // Debug
311
    if (isset($options['d']))
312
        $debug = true;
313
314
    // Domain
315
    if (!isset($options['D']))
316
    {
317
        echo "ERROR: You must provide a Domain\n";
318
        usage($defaultConfigFile);
0 ignored issues
show
Unused Code introduced by
The call to usage() has too many arguments starting with $defaultConfigFile.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
319
    }
320
    $domain = $options['D'];
321
322
    // Activity name
323
    if (!isset($options['A']))
324
    {
325
        echo "ERROR: You must provide an Activity name\n";
326
        usage($defaultConfigFile);
0 ignored issues
show
Unused Code introduced by
The call to usage() has too many arguments starting with $defaultConfigFile.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
327
    }
328
    $activityName = $options['A'];
329
    
330
    $logPath = null;
331
    if (isset($options['l']))
332
    {
333
        $logPath = $options['l'];
334
    }
335
    $cpeLogger = new CpeSdk\CpeLogger($logPath, $activityName, $debug);
336
    
337
    // Activity version
338
    if (!isset($options['V']))
339
    {
340
        echo "ERROR: You must provide an Activity version\n";
341
        usage($defaultConfigFile);
0 ignored issues
show
Unused Code introduced by
The call to usage() has too many arguments starting with $defaultConfigFile.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
342
    }
343
    $activityVersion = $options['V'];
344
    
345
    // Tasklist
346
    if (!isset($options['T']))
347
    {
348
        $taskList = $options['A'].'-'.$options['V'];
349
    } else {
350
        $taskList = $options['T'];
351
    }
352
    
353
    // OVerrride config file
354
    if (isset($options['c']))
355
    {
356
        $cpeLogger->log_out(
357
            "INFO",
358
            basename(__FILE__),
359
            "Config file: '" . $options['c'] . "'");
360
        $defaultConfigFile = $options['c'];
361
    }
362
363
    try {
364
        // Check config file
365
        if (!($config = json_decode(file_get_contents($defaultConfigFile))))
366
        {
367
            print "\n[CONFIG ISSUE]\nConfiguration file '$defaultConfigFile' invalid or non-existant.\n\n[EASY FIX]\nGo to the directory mentioned in the error above and rename the template file 'cpeConfigTemplate.json' to 'cpeConfig.json'. Configure your Activities. As example you have Activities for CloudTranscode already setup in the template. You can declare your Activities and start executing tasks in an SWF workflow.\n";
368
            exit(1);
369
        }
370
    }
371
    catch (Exception $e) {
0 ignored issues
show
Bug introduced by
The class Aws\Swf\Exception does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
372
        print $e;
373
    }
374
            
375
        
376
    # Validate against JSON Schemas
377
    # if (($err = validate_json($config, "config/mainConfig.json")))
0 ignored issues
show
Unused Code Comprehensibility introduced by
62% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
378
    # exit("JSON main configuration file invalid! Details:\n".$err);
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% of this comment could be valid code. Did you maybe forget this after debugging?

Sometimes obsolete code just ends up commented out instead of removed. In this case it is better to remove the code once you have checked you do not need it.

The code might also have been commented out for debugging purposes. In this case it is vital that someone uncomments it again or your project may behave in very unexpected ways in production.

This check looks for comments that seem to be mostly valid code and reports them.

Loading history...
379
380
    return $config;
0 ignored issues
show
Bug introduced by
The variable $config does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
381
}
382
383
// Get config file
384
$defaultConfigFile =
385
    realpath(dirname(__FILE__)) . "/../config/cpeConfig.json";
386
$config = check_input_parameters($defaultConfigFile);
0 ignored issues
show
Unused Code introduced by
The call to check_input_parameters() has too many arguments starting with $defaultConfigFile.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
Bug introduced by
Are you sure the assignment to $config is correct as check_input_parameters($defaultConfigFile) (which targets check_input_parameters()) seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
387
388
// Instantiate ActivityPoller
389
try {
390
    $activityPoller = new ActivityPoller($config);
391
} 
392
catch (CpeSdk\CpeException $e) {
0 ignored issues
show
Bug introduced by
The class SA\CpeSdk\CpeException does not exist. Did you forget a USE statement, or did you not list all dependencies?

Scrutinizer analyzes your composer.json/composer.lock file if available to determine the classes, and functions that are defined by your dependencies.

It seems like the listed class was neither found in your dependencies, nor was it found in the analyzed files in your repository. If you are using some other form of dependency management, you might want to disable this analysis.

Loading history...
393
    $cpeLogger->log_out("FATAL",
394
        basename(__FILE__), $e->getMessage());
395
    exit(1);
396
}
397
398
$cpeLogger->log_out("INFO", basename(__FILE__), "Starting activity tasks polling");
399
400
// Start polling loop
401
while (42)
402
    $activityPoller->poll_for_activities();
403
404