Welcome to Payoneer Jobs Management System.
in this document, you will have a technical overview of how to use the system.
- Important
- Overview
- How To Build
- How To Use
- Usage
- API
- End Points
- Error Handling
- Testing
- UML Design
- Copyrights
- Please note that the system is just to give you an overview of the available skills.
- Please keep in mind that some functions, deployments ideas are just for demonstration purposes while its close to production(not production yet).
- Please note that some functions have been developed to make the system work and are not fully ready to be a production system ex: (JobExecution Types) are limited for testing only and are available to test only internally(ENUM) Class and not available to check without sources like database or properties file.
- due to the small window of time that I have, I hope I can give you ideas about what you're looking for from doing this test.
- all unit tests have been provided in the test package.
- a RESTFul Interface is available along with a rest collection available to import directly to postman.
- the system is Docker ready, you can find more information below.
- the system can be imported directly to Java IDEs Like(IntelliJ).
- the system is using an in-memory Store (H2 database) engine for simplicity, while you can use any RDBMS System like MySQL.
Payoneer's management system has been developed to perform unknown task types. jobs may be ready for direct
execution
or they are queued for future execution.
Payoneer's management system is using Java 16, Spring Boot, Hibernate, Spring JPA, Docker, and H2 Database in its
core.
Payoneer's management system was designed to be highly compatible with any Client (Mobile, Web) while it's using RESTFul
Interface to interact with the outer world.
Payoneer's management system is flexible and upgradable because it uses java interfaces and high-level support to add
new features and components
is just like there is a new feature coming in, extends the old interface, and boom.
Payoneer's management system is built to be a non-blocking Code, using Functional programming at its core. Async RESTFul
APIs is what this system is all about
to build the image just use the following command
docker build -t payoneer_germany/job_management .
to run it
docker run -it -p30000:30000 payoneer_germany/job_management:latest
first make sure we are clean.
gradle clean
then build it.
gradle build
to run it
java -jar JobManagement-1.0.101.jar
note: please check the logs they have enough information about what is happening in the system
-
the system API is quit simple and straightforward
we have an interface that represents the entry point for the entire system, it's CalledJob
before digging in with getting our hands dirty let's first take a look at a few things that are required-
the system is built on top of Spring boot we need to define
beans
to use them in our controllers. -
all of our entity classes must extend the JobBaseEntity class to be valid to us in our system
-
our entity repository must extend the BaseJobRepo to be valid.
-
-
now we are ready let's jump in
we will start by creating an Entity for our Job
- to create a job, create a simple class that extends JobBaseEntity like the following
@Entity
@Table(name = "emails")
public class EmailJob extends BaseJobEntity {
// code here
// columns ...etc.
}
- create a repository.
@Repository
public interface EmailRepo extends BaseJobRepo<EmailJob, UUID> {
// code here.
// repo methods here.
}
- let create our first bean. to have a valid and usable objects
@Bean
public JobService<EmailJob, UUID> jobService(EmailRepo emailRepo){
return new JobService<>(emailRepo);
}
using this bean will initialize the system and pass the entity along with its repository to it.
let's get our hands dirty with the code.
now we can use the system easily, we will start that by creating our fist controller. as mentioned in the overview the
system has a RESTFul Interface.
we will now create our rest controller.
A simple Spring boot Controller is what we are doing here.
@RestController
@RequestMapping("api/v1/job")
public class JobsController {
// code here
}
we will autowire the previous object in this controller to have access to the System.
private final Job<EmailJob, UUID> jobService;
private final EmailRepo emailRepo;
you will have now access using the JobService.
the system contains useful methods that can be chained to perform a task, either the job should be executed directly or
queued.
its quite simple as we will go through that in a sec.
- to create and process a simple task you just need to call createJob(emailJob,executionType, jobPriority) and boom.
// create an object and pass it to the system
var emailJob=new EmailJob(
UUID.randomUUID(),
Instant.now(),
createEmailJobRequest.getEmailJob().getTo(),
createEmailJobRequest.getEmailJob().getSubject(),
createEmailJobRequest.getEmailJob().getName(),
createEmailJobRequest.getEmailJob().getContent(),
executionType,
jobPriority
);
// execute it using:
jobService.createJob(emailJob,executionType,jobPriority)
please note that
createEmailJobRequest
is a POJO class that is used by the rest endpoint to pass JSON objects to the system
json snippet:
{
"emailJob": {
"to": "[email protected]",
"subject": "email job",
"name": "Feras Alawadi",
"content": "hello this is just a demo of Payoneer Germany Job Management System."
},
"executionType": "execute",
"jobPriority": "high"
}
- to schedule a task please use the following:
use the method createJob(emailJob, LocalDateTime) to pass the object and the date of the execution
then make sure to scedule it by calling scheduleJob(JobExecutionType executionType, JobPriority jobPriority)
please note that the method in here is chained in the order createJob() then schedule mess with the order will lead the system to fail and throw error
// create a job object
var emailJob=new EmailJob(
UUID.randomUUID(),
Instant.now(),
scheduleTaskReq.getEmailJob().getTo(),
scheduleTaskReq.getEmailJob().getSubject(),
scheduleTaskReq.getEmailJob().getName(),
scheduleTaskReq.getEmailJob().getContent(),
executionType,
jobPriority
);
// execute it
jobService.createJob(emailJob,scheduleTaskReq.getWhen(),jobPriority).scheduleJob(executionType)
please note to have a valid scheduled task a proper date should be passed of pattern: 2021-09-10T14:30:00
a json snippet
{
"when": "2021-09-10T14:30:00",
"emailJob": {
"to": "[email protected]",
"subject": "email job",
"name": "Feras Alawadi",
"content": "hello this is just a demo of Payoneer Germany Job Management System."
},
"executionType": "QUEUED",
"jobPriority": "high"
}
- cancel a job
job can be canceled easily by calling thecancelJob(id)
method. check it here cancelJob(ID id)
jobService.cancelJob(UUID.fromString(uuid))
please note that to have a valid operation a valid UUID must be passed.
the system already has a Utils Class that have useful methods to help with this obviously
please see ApiUtils for more info
to validate the id you can call the method validUUID(uuid) passing the id to it to check if It''s valid or not.
JobExecutionType and JobPriority are enum classes that contains at least one layer of usage (minimum). please refer to them for more info
the schema of the API is simple and providing a generic shape that can be used to help front end programmers perform
the tasks faster by having one wrapper to the json
in fact what changing here is the body of the results object, to make this clear let's take a look at some samples.
{
"status": true,
"code": "SUCCESS",
"message": "job has been scheduled successfully",
"results": {
"id": "48980659-c876-4dd7-9e32-dd17943c7777",
"created": "2021-09-10T17:15:55.543108200Z",
"modified": null,
"version": 1,
"to": "[email protected]",
"subject": "email job",
"name": "Feras Alawadi",
"content": "hello this is just a demo of Payoneer Germany Job Management System.",
"executionType": "QUEUED"
},
"errors": null
}
as you can see the results object is what changing here each time it has new data depending on what endpoint you are calling.
{
"status": false,
"code": "FAIL",
"message": "job has can't be Canceled",
"results": null,
"errors": {
"errorMessage": "job: { 1aa749aa-4171-4798-b3c2-5f36c008e95b } can't be canceled because it might already proceed or canceled already ",
"errorCode": "FAIL"
}
}
here we have an error object while the results have a null value.
please note that
status
,code
,message
results
errors
are always there in the response
the error object has a fixed shape
"errors": {
"errorMessage": "...",
"errorCode": "..."
}
in conclusion: the value of results
is changing only so the developers need to deal with what it contains.
the url scheam is straight forward as well
URL/api/{version}/group
for example:
http://localhost:30000/api/v1/job
the system is trying its best to deal with all edge cases and unknown user behavior, by responding back with error codes
to the client instead of throwing API Error codes
4xx
and 5xx
, keep in mind in some cases the system must fail to protect the data and the warehouse.
in this case, the system is logging all the things that happen, please refer to the logs to have an idea about the error
codes that appear.
** The idea behind throwing errors **
- is that the system will print the error but will continue to function normally.
- otherwise, normal errors will be returned to the client as API responses.
- the system is already has a Testing REST Interface.
- there is a unit test in the test package that can be used.
- the current system is equipped with the following testing endpoints
URL | usage | Method |
---|---|---|
http://localhost:30000/api/v1/job | Create a Job Task | POST |
http://localhost:30000/api/v1/job/sc | Schedule a Task | POST |
http://localhost:30000/api/v1/job?id=1aa749aa-4171-4798-b3c2-5f36c008e95b | cancel a task | DELETE |
http://localhost:30000/api/v1/job/query?execution_type=EXECUTE | search for data | GET |
http://localhost:30000/api/v1/job | load all tasks | GET |
- unit test is available at the test package that contains tests for the system methods.
Copyright © Payoneer Germany 2021