Feedback
Feedback Processing Service
Processing
What is the Feedback Processing service?
The Feedback Processing service is responsible for analyzing feedback by executing a set of predefined processes called executors. Each feedback item goes through a sequence of analyses, and once all assigned executors have completed, the feedback is considered fully processed.
Executors are organized into execution groups using a group_order column. This allows defining ordered groups of processes where:
- Executors in the same group (
group_order = N) run in parallel. - The next group (
group_order = N+1) starts only if all executors from the previous group have completed successfully.
This mechanism enables more advanced workflows and dependencies between processes, ensuring that certain analyses only start once prerequisite steps are validated.
A central ProcessManager handles the orchestration:
- Executors are dispatched asynchronously via Laravel's job system.
- It ensures group-level execution integrity by waiting for all processes in the current group before moving to the next one.
Important Information
If any executor in a group fails, the next group will not be triggered for that feedback. This guarantees a controlled and ordered flow of analysis.
Using the ProcessManager
To execute the processing for a given feedback instance, instantiate and call the handle() method on the ProcessManager:
use App\Services\Feedback\Processing\ProcessManager;
use App\Models\Feedback;
$feedback = Feedback::find(1); // Retrieve a feedback instance
(new ProcessManager($feedback))->handle();If you need to run only specific processes, you can pass an array of allowed executors:
(new ProcessManager($feedback, ['alpha-score']))->handle();This ensures that only the specified executor(s) will be executed for the given feedback item.
Executors
What is an executor?
An executor is a unit of processing logic that performs a specific analysis on a feedback item or a related model. Executors implement the Executable interface and must define:
- A name to identify them.
- The model they apply to.
- Whether they are applicable to a given model instance.
- Their execution type (e.g., one-time or always).
- The logic for execution.
Executors are stored in app/Services/Feedback/Processing/Executors/.
Registering an Executor
Every executor must be registered in config/feedback.php under the executors key. If an executor is not registered, it will not be recognized by the system.
Example configuration:
'executors' => [
Processing\Executors\SanitizerExecutor::class,
Processing\Executors\NpsProfileExecutor::class,
Processing\Executors\AlphaScoreExecutor::class,
],Create a new executor
Implementation
To create a new executor, extend the Executor abstract class and implement the required methods.
namespace App\Services\Feedback\Processing\Executors;
use App\Services\Feedback\Processing\Executor;
use Illuminate\Database\Eloquent\Model;
class CustomExecutor extends Executor
{
public static function name(): string
{
return 'custom-executor';
}
public static function model(): string
{
return Feedback::class;
}
public static function applicable(Model $model): bool
{
return true; // Define the condition for applicability
}
public function execute(Model $model): void
{
// Execution logic here
}
}Execution Type
Executors must define their execution type using the executions() method:
public static function executions(): ExecutionsEnum
{
return ExecutionsEnum::ONE_TIME; // or ExecutionsEnum::ALWAYS
}- ONE_TIME: The executor runs only once per model instance, even if
ProcessManageris called multiple times. - ALWAYS: The executor runs every time
ProcessManageris executed.
Applicable
The applicable() method determines whether an executor should process a given model instance. If it returns false, no job will be dispatched. This acts as a filtering mechanism.
For example, the Alpha Score calculation applies only to QuestionAnswer models of type textarea. If the condition is not met, the method returns false:
public static function applicable(Model $model): bool
{
return $model->question?->type === QuestionTypeEnum::TEXTAREA->value;
}Model
Each executor is associated with a specific model by defining the model() method. This model must be either the Feedback model itself (Feedback.php) or one of its related models.
The available relations are defined in config/feedback.php:
'model' => \App\Models\Feedback::class,
'relations' => [
'questionAnswers' => \App\Models\QuestionAnswer::class,
'attributeValues' => \App\Models\AttributeValue::class,
],Thus, an executor can be associated with:
Feedback::class→ The executor will run once per feedback.QuestionAnswer::classorAttributeValue::class→ The executor will run independently for each relatedQuestionAnswerorAttributeValueof the feedback.
Configurations
Executor-specific configurations are stored in config/feedback.php under the configurations key. Each executor has its own configuration set, for example:
'configurations' => [
Processing\Executors\AlphaScoreExecutor::class => [
'url' => env('FEEDBACK_ALPHA_SCORE_URL', 'http://91.134.77.15:8000/predict'),
'api_key' => env('FEEDBACK_ALPHA_SCORE_API_KEY'),
],
],Executors can retrieve these configurations using the configurations() method.
Commands
Pause or resume an executor
Executors can be enabled or disabled using CLI commands:
php artisan feedback:processing:enable
php artisan feedback:processing:disableCreate or delete an executor
To create or delete an executor:
php artisan feedback:processing:create
php artisan feedback:processing:deletetitle: Start Feedback Processing
Start Feedback Processing
The feedback:processing:start command interactively starts the processing of feedback using various filters and execution settings. It allows you to define the scope of feedback to process, date range filters, which processes to run, and whether to reset already existing process steps.
Database Structure
The system uses two main tables to track processes:
feedback_processes
Stores information about available executors:
| Column | Type | Description |
|---|---|---|
| id | bigint | Unique identifier |
| executor_name | varchar(255) | Executor name |
| enabled | tinyint(1) | Whether the process is active |
| created_at | timestamp | Creation timestamp |
| updated_at | timestamp | Last update timestamp |
feedback_process_steps
Tracks the execution status of processes for each feedback item:
| Column | Type | Description |
|---|---|---|
| id | bigint | Unique identifier |
| process_id | bigint | Related process ID |
| feedback_id | bigint | Feedback item ID |
| processable_type | varchar(255) | The model type being processed |
| processable_id | bigint | The specific record being processed |
| status | varchar(255) | Execution status (e.g., pending, completed) |
| dispatches | int | Number of dispatch attempts |
| attempts | int | Number of execution attempts |
| last_error_message | longtext | Stores the last encountered error |
| created_at | timestamp | Creation timestamp |
| updated_at | timestamp | Last update timestamp |
This database structure allows tracking each executor's progress and debugging failures efficiently.
This documentation provides a structured guide to understanding, implementing, and managing the Feedback Processing service in Feedier.