Block Aero Backend API uses a micro services based architecture. This API supports the following tasks and they are executed in the order shown below.
Specified execution time (seconds) shown below corresponds to a text PDF file input of 126.6KB. Total execution time for one page in this example is 11.33 seconds
- [x] multi page PDF
- [x] single page PDF
- [x] png image
- [x] text file
2. OCR Pre-Processing (Microservice: ocr-tesseract Execution Time:2.5) - [x] See if the given page has text content or image content - [x] If the page has text content, forcefully convert it into image. The reason being, even though there is text content in the PDF, there could be images. - [x] Create highdpi grayscale image (=>300 DPI) for ocr after repair, clean, orient, deskew - [x] Create a lowdpi grayscale image (72) with 120X120 for thumbnail
Note: We use the same microservice for pre-processing and ocr processing, since both has the same set of dependencies and calling them separately is inefficient and time consuming. Therefore we use a task scheduler within the microservice. This microservice is optimised for a machine with a minimum of 4 cores.
You must use a proper IDE (not Notepad etc) with linting enabled for whatever programming language you use for this repo. For each microservice, you may choose whatever programming language of your choice as it fits the contract to the other microservices.
Development environment: Linux
IDE: Atom Python Version needed on your machine: 3.6.5 Additional requirement in your machine: pip install autopep8
Atom plugins to install:(use Atom settings view) ide-python, linter-python-pep8, language-python Python code does not autofix, the editor will show you the static lint errors only. So you run ./lint.sh path/to/python/file to do linting.
Please make sure you have no lint errors before you commit code. Make sure you make small functions which are testable and a function should do ideally only one 'function'. Make sure you don't have a high cyclomatic dependency lint error. If you have, your function design is not well planned.
IDE: Atom Requirement in your machine: apt-get install shellcheck . Refer to shellcheck Atom plugins to install: language-shellscript, linter-shellcheck
Make sure you have the latest docker running in your machine. Make sure jq is installed in your machine.
Each microservice has one specific objective - nothing more. It expects a specific payload and outputs a specific response.
Make sure the following commands work properly
//this should work without errors
docker ps
//you should see something equal or above 18
docker version
//this should work
jq
Any work you do, ideally make sure you have an issue associated with that, if not, create one with clear definition of work. When you commit, commit only the file related to that issue one at a time.
For example, you changed a file process.py and abc.py where process.py is changed related to issue 7 and abc.py is related to issue 8
git add processs.py
git commit -m 'fix #7'
git add abc.py
git commit -m 'fix #8'
git push origin master (if it is in master)
We have three machines with the same configuration. They will be in AWS with names, api, stage.api and dev.api.
Except for production machine, other machines may or may not be available. When there is no active development, dev.api is to be deleted. Also when in fully production mode and when there is no need for staging testing, stage.api should also be deleted.
This expects that you have aws previleges and has the aws cli configured with the profile name as 'blockaero'.
You need an IAM role with 1) AmazonEC2FullAccess and 2) user_creating_ec2_machine_with_role or an admin role. user_creating_ec2_machine_with_role is a custom role created with the following JSON payload.
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"iam:PassRole",
"iam:ListInstanceProfiles",
"ec2:*"
],
"Resource": "*"
}
]
}
Clone the repo, blockaero-devops and run the following command.
//dev machine
resources/scripts/linux/create_aws_machine_without_iac.sh dev.api
//staging machine
resources/scripts/linux/create_aws_machine_without_iac.sh stage.api
//production machine
resources/scripts/linux/create_aws_machine_without_iac.sh api
The additional step which you need to do is to update the route53 entries for the domain in aws console once the IP address is available. For this you need the IAM policy AWSRoute53FullAccess policy attached to your IAM role or request somebody who has that permission to create the entries.
For example, for dev you need dev.api.block.aero and minio.dev.api.block.aero mapped to the IP address of the dev machine. These entries will already be available, just change the IP address.
To add the domains in route53, navigate to list of hosted zones and click api.block.aero.Click 'Create Record Set'.In the name field, just enter the name of the domain, for example dev. Enter Value field with IP address to create an A record.
First time when you are setting up the machine, you need to update the .bashrc file in the $HOME folder where you are working. For example,
export AIMODELS="/home/lucid/ai-models"
export ROOTDOMAIN="api.block.aero"
With the above configuration, you can deploy the pipeline for example for dev as follows.
./deploy.sh dev
If you just want to make sure all dependencies are available and want to proceed with something else, for example, do s3 sync manually, do the following.
./deploy.sh dev install
You need to make sure you have synced the latest AIMODELS. Following is an example of usage based on the above shown directory structure.
aws s3 sync s3://blockaero-ai-models /home/lucid/ai-models &
Same command as above, except that you add the keyword remove. For example, to remove dev.api, run the following. It will remove all resources connected to that machine.
resources/scripts/linux/create_aws_machine_without_iac.sh dev.api remove
We are using a simplified gitflow in our approach.
$ git branch
dev
$ git remote update
Fetching origin
$ git push origin dev
You should be then pulling dev in your dev endpoint machine and deploy based on the subdomainname.
$ git branch
dev
git checkout -b release/0.1.0 origin/dev
git push origin release/0.1.0
Considerations If you go to GitHub, unlike feature branches, there won't be a notification bar waiting for you to open a new "pull request" for the release branch you've just pushed so you need to do it manually instead. To open a "pull request" for the release branch, hit "New pull request" button, compare master (base dropdown) branch to release/0.1.0 (compare dropdown) branch, write a subject and a description for it. This will open a "pull request" so that it can be reviewed by other team members. If what commits you're preparing to release are fine for the rest of the team members then there is nothing to worry about. This process just shows everyone what will be released. Do not use "Merge pull request" button.
Checkout into master branch.
$ git checkout master
Switched to branch 'master'
Your branch is up-to-date with 'origin/master'.
$ git pull origin master
Do not use --no-ff flag otherwise merge will use "recursive" strategy instead of "fast-forward" and this will lead GitHub to create a "pull request" notification after pushing master branch to remote which is an unwanted behavior.
$ git merge release/0.1.0
$ git tag -a 0.1.0 -m 'Create release tag 0.1.0'
Verify the tag is created
$ git tag
0.1.0
In GitHub, this will also merge and close the "pull request" of remote release branch into master branch however it won't delete it. You'll see that in GitHub.
$ git push origin --tags
Counting objects: 1, done.
Note: Clean up the dev after usage of the specific work if needed (only after testing is over and you have done the corresponding release.)
$ git branch -D dev
git push orign --delete dev
//make sure you have made an entry 127.0.0.1 minio.localhost in your /etc/hosts file
./deploy.sh DEV
// you should be able to see the dev webhook by running the following
docker logs webhook --follow
In this mode, you cannot have any uncommitted code, the script will not deploy for changes you try to deploy directly. Make sure you have tested in a DEV environment first, before you attempt this.
// make sure you have an environment variable for ROOTDOMAIN
// for example, you may set ROOTDOMAIN=api.block.aero in your .bashrc file.
./deploy.sh subdomainname
//you should then be able to access endpoints in https://subdomainname.ROOTDOMAIN
//all minio will be accessible from https://minio.subdomainname.ROOTDOMAIN
//you should have created the necessary entries in aws route53
//./deploy.sh subdomainname will build whatever is in the repo and push to dockerhub before deploying.
//however, you may just want to give the customer the deployment script without the code. or you just want to standup something which is already there.
./deploy.sh subdomainname nobuild
By default when you deploy, only one task will be done at a time. However, you may want to have parallel processing in your production deployment. However, how many you want or can have will depend on the host capacity or other joined machines to the host. We haven't automated that scenario for now. As this service is intended to be deployed by a customer and within his premises and it will greatly depend on the capacity there.
The service to scale for multi tasking is func_gateway. For example, if you wish 5 tasks to run parallelly, you may do as follows.
docker service scale func_gateway=5
As of now, most time consuming process is ocr-tesseract, you may scale that up. We know each will take a maximum of 4 CPUs, so for a 16 core machine, we could do as follows.
docker service scale ocr-tesseract=3
An example combination of scaling may look like the following.
docker service scale func_gateway=30 && docker service scale ocr-tesseract=4 && docker service scale func_queue-worker=10 && docker service scale classify-fasttext=3
object storage function dashboard
If you get an error like "dial tcp 127.0.0.1:8080: getsockopt: connection refused, ", there could be various network reasons. Easy fix is to do the following.
// this is already done automatically in DEV. There is no need to do the following in DEV. Only in PRODUCTION if needed.
docker swarm leave --force
//then deploy again
// In dev environment. If calling 127.0.0.1:8080 to invoke function does not work, your network interface has some issue, use the exact IP which you can get by following.
NODE_ADDRESS="$(docker node inspect "$(docker node ls --format '{{.Hostname}}' --filter 'role=manager')" | jq '.[0].Status.Addr' | tr -d '"')"
docker service logs servicename Ex: docker service logs upload-endpoint docker service ls - lists the services running
For applicable services, papertrail centralized log management is enabled. Please login to papertrail
As the application is a swarm cluster, the name of the machine will be the name underwhich systems will get auto registered.
We are using Object Storage using minion which supports various providers like AWS, Azure etc. During development version (when working locally), same api is used where an object storage is created locally where there is no network traffic.
Blockaero multi-tenant scenario in the future may use various Azure/Object stores. (during mvp release, there is only one client, ie one Object Store in Azure). For each tenant, we use a strategy to run a separate minio service. Minio uses http protocol encapsulated and normal copy operation and sync operation will work.
Although we evaluated the possibility of NFS mount (Network File System) using EMC rexray, currently there is no standard way to have the plugin support multiple Object Stores of the same type (S3FS).
Threfore the solution is to have the minio as a service in swarm, then all file operation to local and mirror using mc (minion client).
Basically you need a webhook, thats it. Easiest way is to run the development environment as normal. Make a note of the ngrock webhook url. Then use that URL as the callback url when you call the api end point.
Content type
Image
Digest
Size
89.6 MB
Last updated
about 6 years ago
docker pull blockaero/pdf2csv:a16559384be15ed4c5a33601187fb549df80e88b