SlideShare uma empresa Scribd logo
1 de 88
Baixar para ler offline
FA S T P H P A P I
W H O A M I
Simone Di Maulo - aka @toretto460
PUGGER
http://toretto.me
A G E N D A
A G E N D A
• Performance
A G E N D A
• Performance
• HTTP
A G E N D A
• Performance
• HTTP
• DB Performance
A G E N D A
• Performance
• HTTP
• DB Performance
• Heavy load tasks
A G E N D A
• Performance
• HTTP
• DB Performance
• Heavy load tasks
R E S P O N S E T I M E X m s
— D O N A L D K N U T H —
“ S T R U C T U R E D P R O G R A M M I N G W I T H G O T O S TAT E M E N T S ”
[…] premature optimization is the root of all evil.
— D O N A L D K N U T H —
“ S T R U C T U R E D P R O G R A M M I N G W I T H G O T O S TAT E M E N T S ”
[…] premature optimization is the root of all evil.
K E E P I N
M I N D
M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E
M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E
M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E
M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E
M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E
M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E
M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E
M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E
M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E
M E A S U R E
M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E
M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E
M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E
M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E
M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E
M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E
M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E
L O A D T E S T S
A PA C H E B E N C H M A R K
ab -n 200 -c 50 -k -g bench.tsv http://my.api.test/v1/pro...
^[1] ^[2] ^[3] ^[4] ^[5]
1. Number of requests
2. Concurrent requests
3. Use the keep-alive connection
4. Write the output ready for gnuplot
5. The URL to call
A PA C H E B E N C H M A R K
## Graph configuration ##
# Set the output format and size
set terminal jpeg size 1280,800
# Set the aspect ratio
set size 1, 1
# Title
set title "Benchmark testing"
# The legend/key position
set key left top
# Draw gridlines on the y axis
set grid y
# Label the x-axis
set xlabel 'seconds'
# Label the y-axis
set ylabel "response time (ms)"
## I/O Configuration
# Specify that the x-series data is time data
set xdata time
# The output file
set output "bench.jpg"
# Specify the *input* format of the time data
set timefmt "%s"
# Specify the *output* format for the x labels
set format x "%S"
# Use tabs as the delimiter instead of spaces
set datafile separator 't'
## Run the Plot
# Plot the data
plot "bench.tsv" every ::2 using 2:5 with points
exit
gnuplot plot.format
• https://blackfire.io
• https://tideways.io
• http://xhprof.io/
• https://symfony.com/doc/current/cookbook/profiler/
index.html
A G E N D A
• Performance
• HTTP
• DB Performance
• Heavy load tasks
HTTP is a “contract”
H T T P I S Y O U R F R I E N D
STATELESS ❤ ORIZONTAL SCALABILITY
CACHING ❤ PERFORMANCE
COMPRESSION ❤ SLOW MOBILE NETWORKS
C A C H I N G
$ curl -I http://my-api.com/users/toretto460
$ curl -I http://my-api.com/users/toretto460
{
“id”: da34gtyu50-lo983,
“username”: “toretto460”,
. . .
}
$ curl -I http://my-api.com/users/toretto460
{
“id”: da34gtyu50-lo983,
“username”: “toretto460”,
. . .
}
HTTP/1.1 200 OK
Connection: keep-alive
Content-Type: application/json; charset=utf-8
Date: Sat, 28 Jul 2015 20:12:45 GMT
Cache-Control: private max-age=600
ETag: 88493f3-4afd-507dd8e0aa030
{
“id”: da34gtyu50-lo983,
“username”: “toretto460”,
. . .
}
$ curl -I http://my-api.com/users/toretto460
HTTP/1.1 200 OK
Connection: keep-alive
Content-Type: application/json; charset=utf-8
Date: Sat, 28 Jul 2015 20:12:45 GMT
Cache-Control: private max-age=600
ETag: 88493f3-4afd-507dd8e0aa030
{
“id”: da34gtyu50-lo983,
“username”: “toretto460”,
. . .
}
$ curl -I http://my-api.com/users/toretto460
HTTP/1.1 200 OK
Connection: keep-alive
Content-Type: application/json; charset=utf-8
Date: Sat, 28 Jul 2015 20:12:45 GMT
Cache-Control: private max-age=600
ETag: 88493f3-4afd-507dd8e0aa030
{
“id”: da34gtyu50-lo983,
“username”: “toretto460”,
. . .
}
$ curl -I http://my-api.com/users/toretto460
HTTP/1.1 200 OK
Connection: keep-alive
Content-Type: application/json; charset=utf-8
Date: Sat, 28 Jul 2015 20:12:45 GMT
Cache-Control: private max-age=600
ETag: 88493f3-4afd-507dd8e0aa030
{
“id”: da34gtyu50-lo983,
“username”: “toretto460”,
. . .
}
$ curl -I http://my-api.com/users/toretto460
HTTP/1.1 200 OK
Connection: keep-alive
Content-Type: application/json; charset=utf-8
Date: Sat, 28 Jul 2015 20:12:45 GMT
Cache-Control: private max-age=600
ETag: 88493f3-4afd-507dd8e0aa030
Avoid same request until 28 Jul 2015 20:22:45 GMT
THE SYMFONY WAY
P L AY W I T H H E A D E R S
public function getAction($userIdentifier, Request $request)
{
$response = new Response();
$user = $this->fetchUser($userIdentifier);
$response->setETag($user->caclulateETag());
// $response->setLastModified($user->getLastUpdateDate());
if ($response->isNotModified($request)) {
return $response;
}
...
}
T O O M U C H
M A G I C I N S I D E
https://developers.google.com/web/fundamentals/performance/optimizing-content-efficiency/http-caching
D ATA C O M P R E S S I O N
HTTP Compression is a set of rules
defined by the protocol which enable network
entities (Client and Server) to exchange
compressed data.
# Apache Configuration File
# ------------------------------------------------------------------------------
# | Compression |
# ------------------------------------------------------------------------------
<IfModule mod_deflate.c>
<IfModule mod_filter.c>
AddOutputFilterByType DEFLATE application/javascript 
application/json 
text/css 
text/html 
text/plain 
text/xml
</IfModule>
</IfModule>
E N A B L E C O M P R E S S I O N
# Apache Configuration File
# ------------------------------------------------------------------------------
# | Compression |
# ------------------------------------------------------------------------------
<IfModule mod_deflate.c>
<IfModule mod_filter.c>
DeflateFilterNote Input input_info
DeflateFilterNote Output output_info
DeflateFilterNote Ratio ratio_info
LogFormat '"%r" %{output_info}n/%{input_info}n (%{ratio_info}n%%)' deflate
CustomLog /var/log/apache2/deflate_log deflate
</IfModule>
</IfModule>
L O G C O M P R E S S I O N
H T T P C O M P R E S S I O N
GET /users/toretto460 HTTP/1.1
Host: www.example.com
Accept-Encoding: gzip, deflate
HTTP/1.1 200 OK
Date: mon, 27 Jul 2015 22:38:34 GMT
Server: Apache/1.3.3.7 (Unix) (Red-Hat/Linux)
Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT
Accept-Ranges: bytes
Content-Length: 438
Connection: close
Content-Type: text/html; charset=UTF-8
Content-Encoding: gzip
H T T P C O M P R E S S I O N
GET /users/toretto460 HTTP/1.1
Host: www.example.com
HTTP/1.1 200 OK
Date: mon, 27 Jul 2015 22:38:34 GMT
Server: Apache/1.3.3.7 (Unix) (Red-Hat/Linux)
Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT
Accept-Ranges: bytes
Content-Length: 438
Connection: close
Content-Type: text/html; charset=UTF-8
Accept-Encoding: gzip, deflate
Content-Encoding: gzip
T H E P O W E R O F H T T P
Client ServerISP Proxy
T H E P O W E R O F H T T P
Client ServerISP Proxy
Client cache
T H E P O W E R O F H T T P
Client ServerISP Proxy
Client cache
Public cache
T H E P O W E R O F H T T P
Client ServerISP Proxy
Client cache
Public cache
Reverse Proxy
Data compression
A G E N D A
• Performance
• HTTP
• DB Performance
• Heavy load tasks
O R M H E R O
T I P S
• AUTO_INCREMENT / SEQUENCE are not so cheap
• Understanding the TRACKING POLICY
• Use READONLY entities
• Let’s CACHE
A U T O _ I N C R E M E N T & S E Q U E N C E S
A R E N O T S O C H E A P
class User
{
/**
* @ORMId
* @ORMColumn(name="ID", type="string", length=37, nullable=false)
* @ORMGeneratedValue(strategy="AUTO")
*/
private $id;
}
A U T O _ I N C R E M E N T & S E Q U E N C E S
A R E N O T S O C H E A P
class User
{
/**
* @ORMId
* @ORMColumn(name="ID", type="string", length=37, nullable=false)
* @ORMGeneratedValue(strategy="AUTO")
*/
private $id;
public function __construct(UserInfoDTO $userInfo)
{
$this->id = (string) Uuid::uuid4();
$this->name = $userInfo->name;
...
}
}
U N D E R S TA N D I N G T H E
T R A C K I N G P O L I C Y
U N D E R S TA N D I N G T H E
T R A C K I N G P O L I C Y
— M A R T I N F O W L E R —
“Maintains a list of objects affected by a business
transaction
and coordinates the writing out of changes and the
resolution of concurrency problems.”
UNIT OF WORK
U N I T O F W O R K
D ATA B A S E
$em->persist($user);
U N I T O F W O R K
D ATA B A S E
$em->persist($user);
U N I T O F W O R K
D ATA B A S E
$em->persist($user);
U N I T O F W O R K
$em->flush();
D ATA B A S E
TRACKING POLICIES
D E F E R R E D I M P L I C I T
With this policy, Doctrine detects the changes by a
property-by-property comparison at commit time and
also detects changes to entities or new entities that are
referenced by other managed entities …
http://doctrine-orm.readthedocs.org/en/latest/reference/change-tracking-policies.html
D E F E R R E D I M P L I C I T
http://doctrine-orm.readthedocs.org/en/latest/reference/change-tracking-policies.html
class User
{
/**
* @ORMId
* @ORMColumn(name="ID", type="string", length=37, nullable=false)
*/
private $id;
/**
* @ORMColumn(name="FIRST_NAME", type="string", length=100, nullable=false)
*/
private $firstName;
/**
* @ORMColumn(name="LAST_NAME", type="string", length=100, nullable=false)
*/
private $lastName;
/**
* @ORMColumn(name="BIRTH_DATE", type="date", nullable=false)
*/
private $birthDate;
}
UOW
$em->flush();
D E F E R R E D E X P L I C I T
… the difference is that Doctrine 2 only considers
entities that have been explicitly marked for change
detection through a call to
EntityManager::persist(entity)
or through a save cascade.
http://doctrine-orm.readthedocs.org/en/latest/reference/change-tracking-policies.html
D E F E R R E D E X P L I C I T
http://doctrine-orm.readthedocs.org/en/latest/reference/change-tracking-policies.html
class User
{
/**
* @ORMId
* @ORMColumn(name="ID", type="string", length=37, nullable=false)
*/
private $id;
/**
* @ORMColumn(name="FIRST_NAME", type="string", length=100, nullable=false)
*/
private $firstName;
/**
* @ORMColumn(name="LAST_NAME", type="string", length=100, nullable=false)
*/
private $lastName;
/**
* @ORMColumn(name="BIRTH_DATE", type="date", nullable=false)
*/
private $birthDate;
}
UOW
$em->persist($user);
$em->flush();
N O T I F Y
This policy is based on the assumption that the entities
notify interested listeners of changes to their properties.
For that purpose, a class that wants to use this policy
needs to implement the NotifyPropertyChanged
interface
http://doctrine-orm.readthedocs.org/en/latest/reference/change-tracking-policies.html
N O T I F Y
<?php
use DoctrineCommonNotifyPropertyChanged,
DoctrineCommonPropertyChangedListener;
/**
* @Entity
* @ChangeTrackingPolicy("NOTIFY")
*/
class User implements NotifyPropertyChanged
{
// ...
private $_listeners = array();
public function addPropertyChangedListener(PropertyChangedListener $listener)
{
$this->_listeners[] = $listener;
}
}
N O T I F Y
<?php
// . . .
protected function _onPropertyChanged($propName, $oldValue, $newValue)
{
if ($this->_listeners) {
foreach ($this->_listeners as $listener) {
$listener->propertyChanged($this, $propName, $oldValue, $newValue);
}
}
}
public function setData($data)
{
if ($data != $this->data) {
$this->_onPropertyChanged('data', $this->data, $data);
$this->data = $data;
}
}
}
U S E R E A D O N LY E N T I T I E S
This means that the entity marked as read only is never
considered for updates
U S E R E A D O N LY E N T I T I E S
/**
* @ORMEntity(readOnly=true)
*/
class NewsTag
{
/**
* @ORMId
* @ORMColumn(name="ID", type="string", length=37, nullable=false)
*/
private $id;
}
L E T ’ S C A C H E
/**
* Configure the Doctrine ORM with a result cache provider.
*/
$config = new DoctrineORMConfiguration();
// The APC way
$apcCacheDriver = new DoctrineCommonCacheApcCache();
$config->setResultCacheImpl($apcCacheDriver);
// The memcache way
$memcache = new Memcache();
$memcache->connect('memcache_host', 11211);
$memCacheDriver = new DoctrineCommonCacheMemcacheCache();
$memCacheDriver->setMemcache($memcache);
$config->setResultCacheImpl($memCacheDriver);
L E T ’ S C A C H E
doctrine:
orm:
metadata_cache_driver: apc
query_cache_driver: apc
result_cache_driver:
type: memcache
host: localhost
port: 11211
L E T ’ S C A C H E
class UserRepository
{
/**
* @return User[]
*/
protected function findLocked()
{
$qb = $this->createQueryBuilder('user');
$qb->where($qb->expr()->eq('user.locked', true));
$query = $qb->getQuery();
$query->useResultCache(true, 60 * 2 /* 2 minutes */);
return $query->getResult();
}
}
R E A L U S E C A S E - # 1 D ATA I M P O R T
> 2 0 0 K E N T I T I E S
SEQUENCE UUID
$em->flush(get_class($entity));
$em->clear(get_class($entity));
R E A L U S E C A S E - # 1 D ATA I M P O R T
> 2 0 0 K E N T I T I E S
R E A L U S E C A S E - # 1 D ATA I M P O R T
> 2 0 0 K E N T I T I E S
208k Entities
loaded in 2h 25m
😟
R E A L U S E C A S E - # 1 D ATA I M P O R T
> 2 0 0 K E N T I T I E S
R E A L U S E C A S E - # 1 D ATA I M P O R T
> 2 0 0 K E N T I T I E S
AFTER THE CURE
208k Entities
loaded in 28 minutes
😊
A G E N D A
• Performance
• HTTP
• DB Performance
• Heavy load tasks
S L O W TA S K
The user avatar should be resized to 300x300px
The administrator should upload up to 250k
orders in a single cvs file
Send an email when a new post has been created
S L O W TA S K
A crawler should find and aggregate product info
Every X minutes the rss feed should be updated
The user can export all the orders
R E A L U S E C A S E - # 2 R E P O R T I N G
R E A L U S E C A S E - # 2 R E P O R T I N G
AS AN analyst
I WANT TO request for a new monthly report
R E A L U S E C A S E - # 2 R E P O R T I N G
AS AN analyst
I WANT TO request for a new monthly report
CREATE TABLE TMP_CFMS_R7_7844 AS SELECT ROWNUM AS ID, x.* FROM (SELECT COD_DEALER, COD_PDV, TOTAL_ACQUISIZIONI,
CONFRONTO_ACQUISIZIONI, AVG_ACQUISIZIONI, PERCENTUALE_INCREMENTO, CAST( NULL AS NUMBER ) QTA_SOGL, CAST( NULL AS
NUMBER ) QTA_SUPE_SOGL, TOTAL_SOSPENSIONI, SOSPENSIONI_CONFRONTO, AVG_SOSPENSIONI, PERCENTUALE_INCREMENTO_SOSP,
CAST( NULL AS NUMBER ) QTA_SOGL_SOSP, CAST( NULL AS NUMBER ) QTA_SUPE_SOGL_SOSP, PERCENTUALE_SOSPENSIONI_ACQU,
PERC_SOSP_ACQU_CONF, PERCENTUALE_SUPERAMENTO, D_RAG_SOC, D_IND, D_LOCALITA, D_CAP, D_PROVINCIA, D_PIVA, INDIRIZZO
V_IND, LOCALITA V_LOCALITA, CAP V_CAP, PROVINCIA V_PROVINCIA FROM ANAGRAFICA_DEALER, (SELECT COD_DEALER, COD_PDV,
TOTAL_ACQUISIZIONI, CONFRONTO_ACQUISIZIONI, AVG_ACQUISIZIONI, PERCENTUALE_INCREMENTO, CAST( NULL AS NUMBER )
QTA_SOGL, CAST( NULL AS NUMBER ) QTA_SUPE_SOGL, TOTAL_SOSPENSIONI, SOSPENSIONI_CONFRONTO, AVG_SOSPENSIONI,
PERCENTUALE_INCREMENTO_SOSP, CAST( NULL AS NUMBER ) QTA_SOGL_SOSP, CAST( NULL AS NUMBER ) QTA_SUPE_SOGL_SOSP,
PERCENTUALE_SOSPENSIONI_ACQU, PERC_SOSP_ACQU_CONF, PERCENTUALE_SUPERAMENTO, RAGSOC D_RAG_SOC, INDIRIZZO D_IND,
LOCALITA D_LOCALITA, CAP D_CAP, PROVINCIA D_PROVINCIA, PIVA D_PIVA FROM ANAGRAFICA_DEALER, (SELECT
A.COD_DEALER,A.COD_PDV,NVL(A.TOTAL_ACQUISIZIONI,'0') TOTAL_ACQUISIZIONI,NVL(A.CONFRONTO_ACQUISIZIONI,'0')
CONFRONTO_ACQUISIZIONI,NVL(B.AVG_ACQUISIZIONI,'0') AVG_ACQUISIZIONI,NVL(B.PERCENTUALE_INCREMENTO,'0')
PERCENTUALE_INCREMENTO, CAST( NULL AS NUMBER ) QTA_SOGL, CAST( NULL AS NUMBER )
QTA_SUPE_SOGL ,NVL(C.TOTAL_SOSPENSIONI,'0') TOTAL_SOSPENSIONI,NVL(C.SOSPENSIONI_CONFRONTO,'0')
SOSPENSIONI_CONFRONTO, NVL(D.AVG_SOSPENSIONI,'0') AVG_SOSPENSIONI,NVL(D.PERCENTUALE_INCREMENTO_SOSP,'0')
PERCENTUALE_INCREMENTO_SOSP, CAST( NULL AS NUMBER ) QTA_SOGL_SOSP, CAST( NULL AS NUMBER )
QTA_SUPE_SOGL_SOSP ,NVL(E.PERCENTUALE_SOSPENSIONI_ACQU,'0') PERCENTUALE_SOSPENSIONI_ACQU,
NVL(PERC_SOSP_ACQU_CONF,'0') PERC_SOSP_ACQU_CONF,NVL(PERCENTUALE_SUPERAMENTO,'0') PERCENTUALE_SUPERAMENTO FROM
(SELECT ROWNUM AS ID, x.* FROM (SELECT COD_DEALER, COD_PDV, TOTAL_ACQUISIZIONI, CONFRONTO_ACQUISIZIONI, CAST( NULL
AS NUMBER ) QTA_SOGL, CAST( NULL AS NUMBER ) QTA_SUPE_SOGL, D_RAG_SOC, D_IND, D_LOCALITA, D_CAP, D_PROVINCIA,
D_PIVA, INDIRIZZO V_IND, LOCALITA V_LOCALITA, CAP V_CAP, PROVINCIA V_PROVINCIA FROM ANAGRAFICA_DEALER, (SELECT
COD_DEALER, COD_PDV, TOTAL_ACQUISIZIONI, CONFRONTO_ACQUISIZIONI, CAST( NULL AS NUMBER ) QTA_SOGL, CAST( NULL AS
NUMBER ) QTA_SUPE_SOGL, RAGSOC D_RAG_SOC, INDIRIZZO D_IND, LOCALITA D_LOCALITA, CAP D_CAP, PROVINCIA D_PROVINCIA,
PIVA D_PIVA FROM ANAGRAFICA_DEALER, ( SELECT
A.COD_DEALER,A.COD_PDV,A.TOTAL_ACQUISIZIONI,NVL(B.TOTAL_ACQUISIZIONI,'0') CONFRONTO_ACQUISIZIONI, CAST( NULL AS
NUMBER ) QTA_SOGL, CAST( NULL AS NUMBER ) QTA_SUPE_SOGL FROM (SELECT A.COD_DEALER,A.COD_PDV,COUNT(A.COD_DEALER)
TOTAL_ACQUISIZIONI, CAST( NULL AS NUMBER ) QTA_SOGL, CAST( NULL AS NUMBER ) QTA_SUPE_SOGL FROM CFMS_ATT A WHERE
A.DATA_ATTIVAZIONE between TO_DATE('2015-06-15 00:00:00','yyyy-mm-dd HH24:MI:SS') AND TO_DATE('2015-06-15
23:59:59','yyyy-mm-dd HH24:MI:SS')
AND A.COD_PDV IS NOT NULL GROUP BY A.COD_DEALER,A.COD_PDV) A LEFT JOIN ( SELECT
COD_DEALER,COD_PDV,COUNT(COD_DEALER) TOTAL_ACQUISIZIONI FROM CFMS_ATT WHERE DATA_ATTIVAZIONE between
TO_DATE('2015-06-16 00:00:00','yyyy-mm-dd HH24:MI:SS') AND TO_DATE('2015-06-16 23:59:59','yyyy-mm-dd HH24:MI:SS')
AND COD_PDV IS NOT NULL GROUP BY COD_DEALER,COD_PDV ) B ON A.COD_DEALER=B.COD_DEALER AND A.COD_PDV=B.COD_PDV) WHERE
COD_DEALER = COD_ID (+)) WHERE COD_PDV = COD_ID (+) ORDER BY COD_DEALER) x ) A FULL OUTER JOIN (SELECT ROWNUM AS
ID, x.* FROM (SELECT COD_DEALER, COD_PDV, ACQUISIZIONI, AVG_ACQUISIZIONI, ACQUISIZIONI_CONFRONTO,
AVG_ACQUISIZIONI_CONFRONTO, PERCENTUALE_INCREMENTO, D_RAG_SOC, D_IND, D_LOCALITA, D_CAP, D_PROVINCIA, D_PIVA,
INDIRIZZO V_IND, LOCALITA V_LOCALITA, CAP V_CAP, PROVINCIA V_PROVINCIA FROM ANAGRAFICA_DEALER, (SELECT COD_DEALER,
COD_PDV, ACQUISIZIONI, AVG_ACQUISIZIONI, ACQUISIZIONI_CONFRONTO, AVG_ACQUISIZIONI_CONFRONTO, PERCENTUALE_INCREMENTO,
RAGSOC D_RAG_SOC, INDIRIZZO D_IND, LOCALITA D_LOCALITA, CAP D_CAP, PROVINCIA D_PROVINCIA, PIVA D_PIVA FROM
ANAGRAFICA_DEALER, ( SELECT A.COD_DEALER,A.COD_PDV,A.ACQUISIZIONI,TO_CHAR(A.AVG_ACQUISIZIONI,'99990D99')
R E A L U S E C A S E - # 2 R E P O R T I N G
AS AN analyst
I WANT TO request for a new monthly report
R E A L U S E C A S E - # 2 R E P O R T I N G
AS AN analyst
I WANT TO request for a new monthly report
SO THAT the system will send me an email
with the attached csv report
R U N I N B A C K G R O U N D
S C A L I N G T H E A S Y N C
Y O U R A P P
I S
H E R E
W O R K E R
W O R K E R
W O R K E R
W O R K E R
Q U E U E
POST /rss
PATCH /users
POST /export
A S Y N C H R O N O U S TA S K
• https://github.com/uecode/qpush-bundle
• https://github.com/videlalvaro/php-amqplib
• https://github.com/videlalvaro/RabbitMqBundle
• http://gearmanbundle.readthedocs.org/en/latest/configuration.html
• https://github.com/chrisboulton/php-resque
T H A N K S
🍻time

Mais conteúdo relacionado

Mais procurados

REST API and CRUD
REST API and CRUDREST API and CRUD
REST API and CRUDPrem Sanil
 
Docker 101 : Introduction to Docker and Containers
Docker 101 : Introduction to Docker and ContainersDocker 101 : Introduction to Docker and Containers
Docker 101 : Introduction to Docker and ContainersYajushi Srivastava
 
Docker Swarm for Beginner
Docker Swarm for BeginnerDocker Swarm for Beginner
Docker Swarm for BeginnerShahzad Masud
 
Building an API with Django and Django REST Framework
Building an API with Django and Django REST FrameworkBuilding an API with Django and Django REST Framework
Building an API with Django and Django REST FrameworkChristopher Foresman
 
Dapr: distributed application runtime
Dapr: distributed application runtimeDapr: distributed application runtime
Dapr: distributed application runtimeMoaid Hathot
 
Docker swarm introduction
Docker swarm introductionDocker swarm introduction
Docker swarm introductionEvan Lin
 
JSON, JSON Schema, and OpenAPI
JSON, JSON Schema, and OpenAPIJSON, JSON Schema, and OpenAPI
JSON, JSON Schema, and OpenAPIOctavian Nadolu
 
Python 테스트 시작하기
Python 테스트 시작하기Python 테스트 시작하기
Python 테스트 시작하기Hosung Lee
 
Express JS Middleware Tutorial
Express JS Middleware TutorialExpress JS Middleware Tutorial
Express JS Middleware TutorialSimplilearn
 
Introduction to Django REST Framework, an easy way to build REST framework in...
Introduction to Django REST Framework, an easy way to build REST framework in...Introduction to Django REST Framework, an easy way to build REST framework in...
Introduction to Django REST Framework, an easy way to build REST framework in...Zhe Li
 
Docker: From Zero to Hero
Docker: From Zero to HeroDocker: From Zero to Hero
Docker: From Zero to Herofazalraja
 
API Design, A Quick Guide to REST, SOAP, gRPC, and GraphQL, By Vahid Rahimian
API Design, A Quick Guide to REST, SOAP, gRPC, and GraphQL, By Vahid RahimianAPI Design, A Quick Guide to REST, SOAP, gRPC, and GraphQL, By Vahid Rahimian
API Design, A Quick Guide to REST, SOAP, gRPC, and GraphQL, By Vahid RahimianVahid Rahimian
 
Profiling - 실시간 대화식 프로파일러
Profiling - 실시간 대화식 프로파일러Profiling - 실시간 대화식 프로파일러
Profiling - 실시간 대화식 프로파일러Heungsub Lee
 
Introduction to WebSockets Presentation
Introduction to WebSockets PresentationIntroduction to WebSockets Presentation
Introduction to WebSockets PresentationJulien LaPointe
 
Understanding REST
Understanding RESTUnderstanding REST
Understanding RESTNitin Pande
 
Inter-Process Communication in Microservices using gRPC
Inter-Process Communication in Microservices using gRPCInter-Process Communication in Microservices using gRPC
Inter-Process Communication in Microservices using gRPCShiju Varghese
 

Mais procurados (20)

REST API and CRUD
REST API and CRUDREST API and CRUD
REST API and CRUD
 
Docker 101 : Introduction to Docker and Containers
Docker 101 : Introduction to Docker and ContainersDocker 101 : Introduction to Docker and Containers
Docker 101 : Introduction to Docker and Containers
 
Docker Swarm for Beginner
Docker Swarm for BeginnerDocker Swarm for Beginner
Docker Swarm for Beginner
 
Building an API with Django and Django REST Framework
Building an API with Django and Django REST FrameworkBuilding an API with Django and Django REST Framework
Building an API with Django and Django REST Framework
 
Dapr: distributed application runtime
Dapr: distributed application runtimeDapr: distributed application runtime
Dapr: distributed application runtime
 
Docker swarm introduction
Docker swarm introductionDocker swarm introduction
Docker swarm introduction
 
Rest API
Rest APIRest API
Rest API
 
JSON, JSON Schema, and OpenAPI
JSON, JSON Schema, and OpenAPIJSON, JSON Schema, and OpenAPI
JSON, JSON Schema, and OpenAPI
 
Python 테스트 시작하기
Python 테스트 시작하기Python 테스트 시작하기
Python 테스트 시작하기
 
Introduction to gRPC
Introduction to gRPCIntroduction to gRPC
Introduction to gRPC
 
Swagger
SwaggerSwagger
Swagger
 
Logstash
LogstashLogstash
Logstash
 
Express JS Middleware Tutorial
Express JS Middleware TutorialExpress JS Middleware Tutorial
Express JS Middleware Tutorial
 
Introduction to Django REST Framework, an easy way to build REST framework in...
Introduction to Django REST Framework, an easy way to build REST framework in...Introduction to Django REST Framework, an easy way to build REST framework in...
Introduction to Django REST Framework, an easy way to build REST framework in...
 
Docker: From Zero to Hero
Docker: From Zero to HeroDocker: From Zero to Hero
Docker: From Zero to Hero
 
API Design, A Quick Guide to REST, SOAP, gRPC, and GraphQL, By Vahid Rahimian
API Design, A Quick Guide to REST, SOAP, gRPC, and GraphQL, By Vahid RahimianAPI Design, A Quick Guide to REST, SOAP, gRPC, and GraphQL, By Vahid Rahimian
API Design, A Quick Guide to REST, SOAP, gRPC, and GraphQL, By Vahid Rahimian
 
Profiling - 실시간 대화식 프로파일러
Profiling - 실시간 대화식 프로파일러Profiling - 실시간 대화식 프로파일러
Profiling - 실시간 대화식 프로파일러
 
Introduction to WebSockets Presentation
Introduction to WebSockets PresentationIntroduction to WebSockets Presentation
Introduction to WebSockets Presentation
 
Understanding REST
Understanding RESTUnderstanding REST
Understanding REST
 
Inter-Process Communication in Microservices using gRPC
Inter-Process Communication in Microservices using gRPCInter-Process Communication in Microservices using gRPC
Inter-Process Communication in Microservices using gRPC
 

Semelhante a Fast api

Meteor - not just for rockstars
Meteor - not just for rockstarsMeteor - not just for rockstars
Meteor - not just for rockstarsStephan Hochhaus
 
Spring Roo 2.0 Preview at Spring I/O 2016
Spring Roo 2.0 Preview at Spring I/O 2016 Spring Roo 2.0 Preview at Spring I/O 2016
Spring Roo 2.0 Preview at Spring I/O 2016 DISID
 
Asynchronous data processing
Asynchronous data processingAsynchronous data processing
Asynchronous data processingAndrea Giuliano
 
톰캣 #05+a-배치-parallel deployment
톰캣 #05+a-배치-parallel deployment톰캣 #05+a-배치-parallel deployment
톰캣 #05+a-배치-parallel deploymentGyuSeok Lee
 
2014 06-23 velocity sc beyond page metrics
2014 06-23 velocity sc beyond page metrics2014 06-23 velocity sc beyond page metrics
2014 06-23 velocity sc beyond page metricsBuddy Brewer
 
Designing a Horizontally Scalable Event-Driven Big Data Architecture with Apa...
Designing a Horizontally Scalable Event-Driven Big Data Architecture with Apa...Designing a Horizontally Scalable Event-Driven Big Data Architecture with Apa...
Designing a Horizontally Scalable Event-Driven Big Data Architecture with Apa...Ricardo Fanjul Fandiño
 
PyLadies Talk: Learn to love the command line!
PyLadies Talk: Learn to love the command line!PyLadies Talk: Learn to love the command line!
PyLadies Talk: Learn to love the command line!Blanca Mancilla
 
WordPress in 30 minutes
WordPress in 30 minutesWordPress in 30 minutes
WordPress in 30 minutesOwen Winkler
 
An Introduction to CSS Preprocessors
An Introduction to CSS PreprocessorsAn Introduction to CSS Preprocessors
An Introduction to CSS PreprocessorsMiloš Sutanovac
 
AWS Seminar Series 2015 Melbourne
AWS Seminar Series 2015 MelbourneAWS Seminar Series 2015 Melbourne
AWS Seminar Series 2015 MelbourneAmazon Web Services
 
AWS Seminar Series 2015 Brisbane
AWS Seminar Series 2015 BrisbaneAWS Seminar Series 2015 Brisbane
AWS Seminar Series 2015 BrisbaneAmazon Web Services
 
Representing Material Culture Online: Historic Clothing in Omeka
Representing Material Culture Online: Historic Clothing in OmekaRepresenting Material Culture Online: Historic Clothing in Omeka
Representing Material Culture Online: Historic Clothing in OmekaArden Kirkland
 
Microservices With Spring Boot and Spring Cloud Netflix
Microservices With Spring Boot and Spring Cloud NetflixMicroservices With Spring Boot and Spring Cloud Netflix
Microservices With Spring Boot and Spring Cloud NetflixKrzysztof Sobkowiak
 

Semelhante a Fast api (20)

Meteor - not just for rockstars
Meteor - not just for rockstarsMeteor - not just for rockstars
Meteor - not just for rockstars
 
Spring Roo 2.0 Preview at Spring I/O 2016
Spring Roo 2.0 Preview at Spring I/O 2016 Spring Roo 2.0 Preview at Spring I/O 2016
Spring Roo 2.0 Preview at Spring I/O 2016
 
Meteor WWNRW Intro
Meteor WWNRW IntroMeteor WWNRW Intro
Meteor WWNRW Intro
 
Asynchronous data processing
Asynchronous data processingAsynchronous data processing
Asynchronous data processing
 
톰캣 #05+a-배치-parallel deployment
톰캣 #05+a-배치-parallel deployment톰캣 #05+a-배치-parallel deployment
톰캣 #05+a-배치-parallel deployment
 
2014 06-23 velocity sc beyond page metrics
2014 06-23 velocity sc beyond page metrics2014 06-23 velocity sc beyond page metrics
2014 06-23 velocity sc beyond page metrics
 
Designing a Horizontally Scalable Event-Driven Big Data Architecture with Apa...
Designing a Horizontally Scalable Event-Driven Big Data Architecture with Apa...Designing a Horizontally Scalable Event-Driven Big Data Architecture with Apa...
Designing a Horizontally Scalable Event-Driven Big Data Architecture with Apa...
 
PyLadies Talk: Learn to love the command line!
PyLadies Talk: Learn to love the command line!PyLadies Talk: Learn to love the command line!
PyLadies Talk: Learn to love the command line!
 
GraphQL, l'avenir du REST ?
GraphQL, l'avenir du REST ?GraphQL, l'avenir du REST ?
GraphQL, l'avenir du REST ?
 
WordPress in 30 minutes
WordPress in 30 minutesWordPress in 30 minutes
WordPress in 30 minutes
 
An Introduction to CSS Preprocessors
An Introduction to CSS PreprocessorsAn Introduction to CSS Preprocessors
An Introduction to CSS Preprocessors
 
AWS SEMINAR SERIES 2015 Perth
AWS SEMINAR SERIES 2015 PerthAWS SEMINAR SERIES 2015 Perth
AWS SEMINAR SERIES 2015 Perth
 
rpm-building-101.pdf
rpm-building-101.pdfrpm-building-101.pdf
rpm-building-101.pdf
 
AWS SeMINAR SERIES 2015 Sydney
AWS SeMINAR SERIES 2015 SydneyAWS SeMINAR SERIES 2015 Sydney
AWS SeMINAR SERIES 2015 Sydney
 
AWS Seminar Series 2015 Melbourne
AWS Seminar Series 2015 MelbourneAWS Seminar Series 2015 Melbourne
AWS Seminar Series 2015 Melbourne
 
Auckland AWS Seminar Series
Auckland AWS Seminar SeriesAuckland AWS Seminar Series
Auckland AWS Seminar Series
 
AWS Seminar Series 2015 Brisbane
AWS Seminar Series 2015 BrisbaneAWS Seminar Series 2015 Brisbane
AWS Seminar Series 2015 Brisbane
 
Representing Material Culture Online: Historic Clothing in Omeka
Representing Material Culture Online: Historic Clothing in OmekaRepresenting Material Culture Online: Historic Clothing in Omeka
Representing Material Culture Online: Historic Clothing in Omeka
 
Microservices With Spring Boot and Spring Cloud Netflix
Microservices With Spring Boot and Spring Cloud NetflixMicroservices With Spring Boot and Spring Cloud Netflix
Microservices With Spring Boot and Spring Cloud Netflix
 
eHarmony @ Phoenix Con 2016
eHarmony @ Phoenix Con 2016eHarmony @ Phoenix Con 2016
eHarmony @ Phoenix Con 2016
 

Mais de Simone Di Maulo

The dark side of the app
The dark side of the appThe dark side of the app
The dark side of the appSimone Di Maulo
 
On fuctional programming, high order functions, ML
On fuctional programming, high order functions, MLOn fuctional programming, high order functions, ML
On fuctional programming, high order functions, MLSimone Di Maulo
 
Processing asyncrono dei dati - Symfony2 ❤ Message Queuing
Processing asyncrono dei dati - Symfony2 ❤ Message QueuingProcessing asyncrono dei dati - Symfony2 ❤ Message Queuing
Processing asyncrono dei dati - Symfony2 ❤ Message QueuingSimone Di Maulo
 

Mais de Simone Di Maulo (6)

Orm hero
Orm heroOrm hero
Orm hero
 
PHP Generators
PHP GeneratorsPHP Generators
PHP Generators
 
Docker cqrs react
Docker cqrs reactDocker cqrs react
Docker cqrs react
 
The dark side of the app
The dark side of the appThe dark side of the app
The dark side of the app
 
On fuctional programming, high order functions, ML
On fuctional programming, high order functions, MLOn fuctional programming, high order functions, ML
On fuctional programming, high order functions, ML
 
Processing asyncrono dei dati - Symfony2 ❤ Message Queuing
Processing asyncrono dei dati - Symfony2 ❤ Message QueuingProcessing asyncrono dei dati - Symfony2 ❤ Message Queuing
Processing asyncrono dei dati - Symfony2 ❤ Message Queuing
 

Último

🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘RTylerCroy
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024The Digital Insurer
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...Neo4j
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Drew Madelung
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfEnterprise Knowledge
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024The Digital Insurer
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024The Digital Insurer
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerThousandEyes
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...Martijn de Jong
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsEnterprise Knowledge
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEarley Information Science
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProduct Anonymous
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationRadu Cotescu
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...apidays
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptxHampshireHUG
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 

Último (20)

🐬 The future of MySQL is Postgres 🐘
🐬  The future of MySQL is Postgres   🐘🐬  The future of MySQL is Postgres   🐘
🐬 The future of MySQL is Postgres 🐘
 
Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024Axa Assurance Maroc - Insurer Innovation Award 2024
Axa Assurance Maroc - Insurer Innovation Award 2024
 
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...Workshop - Best of Both Worlds_ Combine  KG and Vector search for  enhanced R...
Workshop - Best of Both Worlds_ Combine KG and Vector search for enhanced R...
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
Strategies for Unlocking Knowledge Management in Microsoft 365 in the Copilot...
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdfThe Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
The Role of Taxonomy and Ontology in Semantic Layers - Heather Hedden.pdf
 
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law DevelopmentsTrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
TrustArc Webinar - Stay Ahead of US State Data Privacy Law Developments
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024Finology Group – Insurtech Innovation Award 2024
Finology Group – Insurtech Innovation Award 2024
 
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
Bajaj Allianz Life Insurance Company - Insurer Innovation Award 2024
 
How to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected WorkerHow to Troubleshoot Apps for the Modern Connected Worker
How to Troubleshoot Apps for the Modern Connected Worker
 
2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...2024: Domino Containers - The Next Step. News from the Domino Container commu...
2024: Domino Containers - The Next Step. News from the Domino Container commu...
 
IAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI SolutionsIAC 2024 - IA Fast Track to Search Focused AI Solutions
IAC 2024 - IA Fast Track to Search Focused AI Solutions
 
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptxEIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
EIS-Webinar-Prompt-Knowledge-Eng-2024-04-08.pptx
 
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemkeProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
ProductAnonymous-April2024-WinProductDiscovery-MelissaKlemke
 
Scaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organizationScaling API-first – The story of a global engineering organization
Scaling API-first – The story of a global engineering organization
 
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
Apidays Singapore 2024 - Building Digital Trust in a Digital Economy by Veron...
 
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
04-2024-HHUG-Sales-and-Marketing-Alignment.pptx
 
08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 

Fast api

  • 1. FA S T P H P A P I
  • 2. W H O A M I Simone Di Maulo - aka @toretto460 PUGGER http://toretto.me
  • 3. A G E N D A
  • 4. A G E N D A • Performance
  • 5. A G E N D A • Performance • HTTP
  • 6. A G E N D A • Performance • HTTP • DB Performance
  • 7. A G E N D A • Performance • HTTP • DB Performance • Heavy load tasks
  • 8. A G E N D A • Performance • HTTP • DB Performance • Heavy load tasks
  • 9. R E S P O N S E T I M E X m s
  • 10. — D O N A L D K N U T H — “ S T R U C T U R E D P R O G R A M M I N G W I T H G O T O S TAT E M E N T S ” […] premature optimization is the root of all evil.
  • 11. — D O N A L D K N U T H — “ S T R U C T U R E D P R O G R A M M I N G W I T H G O T O S TAT E M E N T S ” […] premature optimization is the root of all evil. K E E P I N M I N D
  • 12. M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E M E A S U R E
  • 13. L O A D T E S T S
  • 14.
  • 15.
  • 16. A PA C H E B E N C H M A R K ab -n 200 -c 50 -k -g bench.tsv http://my.api.test/v1/pro... ^[1] ^[2] ^[3] ^[4] ^[5] 1. Number of requests 2. Concurrent requests 3. Use the keep-alive connection 4. Write the output ready for gnuplot 5. The URL to call
  • 17. A PA C H E B E N C H M A R K ## Graph configuration ## # Set the output format and size set terminal jpeg size 1280,800 # Set the aspect ratio set size 1, 1 # Title set title "Benchmark testing" # The legend/key position set key left top # Draw gridlines on the y axis set grid y # Label the x-axis set xlabel 'seconds' # Label the y-axis set ylabel "response time (ms)" ## I/O Configuration # Specify that the x-series data is time data set xdata time # The output file set output "bench.jpg" # Specify the *input* format of the time data set timefmt "%s" # Specify the *output* format for the x labels set format x "%S" # Use tabs as the delimiter instead of spaces set datafile separator 't' ## Run the Plot # Plot the data plot "bench.tsv" every ::2 using 2:5 with points exit
  • 19. • https://blackfire.io • https://tideways.io • http://xhprof.io/ • https://symfony.com/doc/current/cookbook/profiler/ index.html
  • 20. A G E N D A • Performance • HTTP • DB Performance • Heavy load tasks
  • 21. HTTP is a “contract”
  • 22. H T T P I S Y O U R F R I E N D
  • 23. STATELESS ❤ ORIZONTAL SCALABILITY
  • 25. COMPRESSION ❤ SLOW MOBILE NETWORKS
  • 26. C A C H I N G
  • 27. $ curl -I http://my-api.com/users/toretto460
  • 28. $ curl -I http://my-api.com/users/toretto460 { “id”: da34gtyu50-lo983, “username”: “toretto460”, . . . }
  • 29. $ curl -I http://my-api.com/users/toretto460 { “id”: da34gtyu50-lo983, “username”: “toretto460”, . . . } HTTP/1.1 200 OK Connection: keep-alive Content-Type: application/json; charset=utf-8 Date: Sat, 28 Jul 2015 20:12:45 GMT Cache-Control: private max-age=600 ETag: 88493f3-4afd-507dd8e0aa030
  • 30. { “id”: da34gtyu50-lo983, “username”: “toretto460”, . . . } $ curl -I http://my-api.com/users/toretto460 HTTP/1.1 200 OK Connection: keep-alive Content-Type: application/json; charset=utf-8 Date: Sat, 28 Jul 2015 20:12:45 GMT Cache-Control: private max-age=600 ETag: 88493f3-4afd-507dd8e0aa030
  • 31. { “id”: da34gtyu50-lo983, “username”: “toretto460”, . . . } $ curl -I http://my-api.com/users/toretto460 HTTP/1.1 200 OK Connection: keep-alive Content-Type: application/json; charset=utf-8 Date: Sat, 28 Jul 2015 20:12:45 GMT Cache-Control: private max-age=600 ETag: 88493f3-4afd-507dd8e0aa030
  • 32. { “id”: da34gtyu50-lo983, “username”: “toretto460”, . . . } $ curl -I http://my-api.com/users/toretto460 HTTP/1.1 200 OK Connection: keep-alive Content-Type: application/json; charset=utf-8 Date: Sat, 28 Jul 2015 20:12:45 GMT Cache-Control: private max-age=600 ETag: 88493f3-4afd-507dd8e0aa030
  • 33. { “id”: da34gtyu50-lo983, “username”: “toretto460”, . . . } $ curl -I http://my-api.com/users/toretto460 HTTP/1.1 200 OK Connection: keep-alive Content-Type: application/json; charset=utf-8 Date: Sat, 28 Jul 2015 20:12:45 GMT Cache-Control: private max-age=600 ETag: 88493f3-4afd-507dd8e0aa030 Avoid same request until 28 Jul 2015 20:22:45 GMT
  • 35. P L AY W I T H H E A D E R S public function getAction($userIdentifier, Request $request) { $response = new Response(); $user = $this->fetchUser($userIdentifier); $response->setETag($user->caclulateETag()); // $response->setLastModified($user->getLastUpdateDate()); if ($response->isNotModified($request)) { return $response; } ... } T O O M U C H M A G I C I N S I D E
  • 37. D ATA C O M P R E S S I O N
  • 38. HTTP Compression is a set of rules defined by the protocol which enable network entities (Client and Server) to exchange compressed data.
  • 39. # Apache Configuration File # ------------------------------------------------------------------------------ # | Compression | # ------------------------------------------------------------------------------ <IfModule mod_deflate.c> <IfModule mod_filter.c> AddOutputFilterByType DEFLATE application/javascript application/json text/css text/html text/plain text/xml </IfModule> </IfModule> E N A B L E C O M P R E S S I O N
  • 40. # Apache Configuration File # ------------------------------------------------------------------------------ # | Compression | # ------------------------------------------------------------------------------ <IfModule mod_deflate.c> <IfModule mod_filter.c> DeflateFilterNote Input input_info DeflateFilterNote Output output_info DeflateFilterNote Ratio ratio_info LogFormat '"%r" %{output_info}n/%{input_info}n (%{ratio_info}n%%)' deflate CustomLog /var/log/apache2/deflate_log deflate </IfModule> </IfModule> L O G C O M P R E S S I O N
  • 41. H T T P C O M P R E S S I O N GET /users/toretto460 HTTP/1.1 Host: www.example.com Accept-Encoding: gzip, deflate HTTP/1.1 200 OK Date: mon, 27 Jul 2015 22:38:34 GMT Server: Apache/1.3.3.7 (Unix) (Red-Hat/Linux) Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT Accept-Ranges: bytes Content-Length: 438 Connection: close Content-Type: text/html; charset=UTF-8 Content-Encoding: gzip
  • 42. H T T P C O M P R E S S I O N GET /users/toretto460 HTTP/1.1 Host: www.example.com HTTP/1.1 200 OK Date: mon, 27 Jul 2015 22:38:34 GMT Server: Apache/1.3.3.7 (Unix) (Red-Hat/Linux) Last-Modified: Wed, 08 Jan 2003 23:11:55 GMT Accept-Ranges: bytes Content-Length: 438 Connection: close Content-Type: text/html; charset=UTF-8 Accept-Encoding: gzip, deflate Content-Encoding: gzip
  • 43. T H E P O W E R O F H T T P Client ServerISP Proxy
  • 44. T H E P O W E R O F H T T P Client ServerISP Proxy Client cache
  • 45. T H E P O W E R O F H T T P Client ServerISP Proxy Client cache Public cache
  • 46. T H E P O W E R O F H T T P Client ServerISP Proxy Client cache Public cache Reverse Proxy Data compression
  • 47. A G E N D A • Performance • HTTP • DB Performance • Heavy load tasks
  • 48. O R M H E R O
  • 49. T I P S • AUTO_INCREMENT / SEQUENCE are not so cheap • Understanding the TRACKING POLICY • Use READONLY entities • Let’s CACHE
  • 50. A U T O _ I N C R E M E N T & S E Q U E N C E S A R E N O T S O C H E A P class User { /** * @ORMId * @ORMColumn(name="ID", type="string", length=37, nullable=false) * @ORMGeneratedValue(strategy="AUTO") */ private $id; }
  • 51. A U T O _ I N C R E M E N T & S E Q U E N C E S A R E N O T S O C H E A P class User { /** * @ORMId * @ORMColumn(name="ID", type="string", length=37, nullable=false) * @ORMGeneratedValue(strategy="AUTO") */ private $id; public function __construct(UserInfoDTO $userInfo) { $this->id = (string) Uuid::uuid4(); $this->name = $userInfo->name; ... } }
  • 52. U N D E R S TA N D I N G T H E T R A C K I N G P O L I C Y
  • 53. U N D E R S TA N D I N G T H E T R A C K I N G P O L I C Y — M A R T I N F O W L E R — “Maintains a list of objects affected by a business transaction and coordinates the writing out of changes and the resolution of concurrency problems.” UNIT OF WORK
  • 54. U N I T O F W O R K D ATA B A S E
  • 55. $em->persist($user); U N I T O F W O R K D ATA B A S E
  • 56. $em->persist($user); U N I T O F W O R K D ATA B A S E
  • 57. $em->persist($user); U N I T O F W O R K $em->flush(); D ATA B A S E
  • 59. D E F E R R E D I M P L I C I T With this policy, Doctrine detects the changes by a property-by-property comparison at commit time and also detects changes to entities or new entities that are referenced by other managed entities … http://doctrine-orm.readthedocs.org/en/latest/reference/change-tracking-policies.html
  • 60. D E F E R R E D I M P L I C I T http://doctrine-orm.readthedocs.org/en/latest/reference/change-tracking-policies.html class User { /** * @ORMId * @ORMColumn(name="ID", type="string", length=37, nullable=false) */ private $id; /** * @ORMColumn(name="FIRST_NAME", type="string", length=100, nullable=false) */ private $firstName; /** * @ORMColumn(name="LAST_NAME", type="string", length=100, nullable=false) */ private $lastName; /** * @ORMColumn(name="BIRTH_DATE", type="date", nullable=false) */ private $birthDate; } UOW $em->flush();
  • 61. D E F E R R E D E X P L I C I T … the difference is that Doctrine 2 only considers entities that have been explicitly marked for change detection through a call to EntityManager::persist(entity) or through a save cascade. http://doctrine-orm.readthedocs.org/en/latest/reference/change-tracking-policies.html
  • 62. D E F E R R E D E X P L I C I T http://doctrine-orm.readthedocs.org/en/latest/reference/change-tracking-policies.html class User { /** * @ORMId * @ORMColumn(name="ID", type="string", length=37, nullable=false) */ private $id; /** * @ORMColumn(name="FIRST_NAME", type="string", length=100, nullable=false) */ private $firstName; /** * @ORMColumn(name="LAST_NAME", type="string", length=100, nullable=false) */ private $lastName; /** * @ORMColumn(name="BIRTH_DATE", type="date", nullable=false) */ private $birthDate; } UOW $em->persist($user); $em->flush();
  • 63. N O T I F Y This policy is based on the assumption that the entities notify interested listeners of changes to their properties. For that purpose, a class that wants to use this policy needs to implement the NotifyPropertyChanged interface http://doctrine-orm.readthedocs.org/en/latest/reference/change-tracking-policies.html
  • 64. N O T I F Y <?php use DoctrineCommonNotifyPropertyChanged, DoctrineCommonPropertyChangedListener; /** * @Entity * @ChangeTrackingPolicy("NOTIFY") */ class User implements NotifyPropertyChanged { // ... private $_listeners = array(); public function addPropertyChangedListener(PropertyChangedListener $listener) { $this->_listeners[] = $listener; } }
  • 65. N O T I F Y <?php // . . . protected function _onPropertyChanged($propName, $oldValue, $newValue) { if ($this->_listeners) { foreach ($this->_listeners as $listener) { $listener->propertyChanged($this, $propName, $oldValue, $newValue); } } } public function setData($data) { if ($data != $this->data) { $this->_onPropertyChanged('data', $this->data, $data); $this->data = $data; } } }
  • 66. U S E R E A D O N LY E N T I T I E S This means that the entity marked as read only is never considered for updates
  • 67. U S E R E A D O N LY E N T I T I E S /** * @ORMEntity(readOnly=true) */ class NewsTag { /** * @ORMId * @ORMColumn(name="ID", type="string", length=37, nullable=false) */ private $id; }
  • 68. L E T ’ S C A C H E /** * Configure the Doctrine ORM with a result cache provider. */ $config = new DoctrineORMConfiguration(); // The APC way $apcCacheDriver = new DoctrineCommonCacheApcCache(); $config->setResultCacheImpl($apcCacheDriver); // The memcache way $memcache = new Memcache(); $memcache->connect('memcache_host', 11211); $memCacheDriver = new DoctrineCommonCacheMemcacheCache(); $memCacheDriver->setMemcache($memcache); $config->setResultCacheImpl($memCacheDriver);
  • 69. L E T ’ S C A C H E doctrine: orm: metadata_cache_driver: apc query_cache_driver: apc result_cache_driver: type: memcache host: localhost port: 11211
  • 70. L E T ’ S C A C H E class UserRepository { /** * @return User[] */ protected function findLocked() { $qb = $this->createQueryBuilder('user'); $qb->where($qb->expr()->eq('user.locked', true)); $query = $qb->getQuery(); $query->useResultCache(true, 60 * 2 /* 2 minutes */); return $query->getResult(); } }
  • 71. R E A L U S E C A S E - # 1 D ATA I M P O R T > 2 0 0 K E N T I T I E S SEQUENCE UUID $em->flush(get_class($entity)); $em->clear(get_class($entity));
  • 72. R E A L U S E C A S E - # 1 D ATA I M P O R T > 2 0 0 K E N T I T I E S
  • 73. R E A L U S E C A S E - # 1 D ATA I M P O R T > 2 0 0 K E N T I T I E S 208k Entities loaded in 2h 25m 😟
  • 74. R E A L U S E C A S E - # 1 D ATA I M P O R T > 2 0 0 K E N T I T I E S
  • 75. R E A L U S E C A S E - # 1 D ATA I M P O R T > 2 0 0 K E N T I T I E S AFTER THE CURE 208k Entities loaded in 28 minutes 😊
  • 76. A G E N D A • Performance • HTTP • DB Performance • Heavy load tasks
  • 77. S L O W TA S K The user avatar should be resized to 300x300px The administrator should upload up to 250k orders in a single cvs file Send an email when a new post has been created
  • 78. S L O W TA S K A crawler should find and aggregate product info Every X minutes the rss feed should be updated The user can export all the orders
  • 79. R E A L U S E C A S E - # 2 R E P O R T I N G
  • 80. R E A L U S E C A S E - # 2 R E P O R T I N G AS AN analyst I WANT TO request for a new monthly report
  • 81. R E A L U S E C A S E - # 2 R E P O R T I N G AS AN analyst I WANT TO request for a new monthly report CREATE TABLE TMP_CFMS_R7_7844 AS SELECT ROWNUM AS ID, x.* FROM (SELECT COD_DEALER, COD_PDV, TOTAL_ACQUISIZIONI, CONFRONTO_ACQUISIZIONI, AVG_ACQUISIZIONI, PERCENTUALE_INCREMENTO, CAST( NULL AS NUMBER ) QTA_SOGL, CAST( NULL AS NUMBER ) QTA_SUPE_SOGL, TOTAL_SOSPENSIONI, SOSPENSIONI_CONFRONTO, AVG_SOSPENSIONI, PERCENTUALE_INCREMENTO_SOSP, CAST( NULL AS NUMBER ) QTA_SOGL_SOSP, CAST( NULL AS NUMBER ) QTA_SUPE_SOGL_SOSP, PERCENTUALE_SOSPENSIONI_ACQU, PERC_SOSP_ACQU_CONF, PERCENTUALE_SUPERAMENTO, D_RAG_SOC, D_IND, D_LOCALITA, D_CAP, D_PROVINCIA, D_PIVA, INDIRIZZO V_IND, LOCALITA V_LOCALITA, CAP V_CAP, PROVINCIA V_PROVINCIA FROM ANAGRAFICA_DEALER, (SELECT COD_DEALER, COD_PDV, TOTAL_ACQUISIZIONI, CONFRONTO_ACQUISIZIONI, AVG_ACQUISIZIONI, PERCENTUALE_INCREMENTO, CAST( NULL AS NUMBER ) QTA_SOGL, CAST( NULL AS NUMBER ) QTA_SUPE_SOGL, TOTAL_SOSPENSIONI, SOSPENSIONI_CONFRONTO, AVG_SOSPENSIONI, PERCENTUALE_INCREMENTO_SOSP, CAST( NULL AS NUMBER ) QTA_SOGL_SOSP, CAST( NULL AS NUMBER ) QTA_SUPE_SOGL_SOSP, PERCENTUALE_SOSPENSIONI_ACQU, PERC_SOSP_ACQU_CONF, PERCENTUALE_SUPERAMENTO, RAGSOC D_RAG_SOC, INDIRIZZO D_IND, LOCALITA D_LOCALITA, CAP D_CAP, PROVINCIA D_PROVINCIA, PIVA D_PIVA FROM ANAGRAFICA_DEALER, (SELECT A.COD_DEALER,A.COD_PDV,NVL(A.TOTAL_ACQUISIZIONI,'0') TOTAL_ACQUISIZIONI,NVL(A.CONFRONTO_ACQUISIZIONI,'0') CONFRONTO_ACQUISIZIONI,NVL(B.AVG_ACQUISIZIONI,'0') AVG_ACQUISIZIONI,NVL(B.PERCENTUALE_INCREMENTO,'0') PERCENTUALE_INCREMENTO, CAST( NULL AS NUMBER ) QTA_SOGL, CAST( NULL AS NUMBER ) QTA_SUPE_SOGL ,NVL(C.TOTAL_SOSPENSIONI,'0') TOTAL_SOSPENSIONI,NVL(C.SOSPENSIONI_CONFRONTO,'0') SOSPENSIONI_CONFRONTO, NVL(D.AVG_SOSPENSIONI,'0') AVG_SOSPENSIONI,NVL(D.PERCENTUALE_INCREMENTO_SOSP,'0') PERCENTUALE_INCREMENTO_SOSP, CAST( NULL AS NUMBER ) QTA_SOGL_SOSP, CAST( NULL AS NUMBER ) QTA_SUPE_SOGL_SOSP ,NVL(E.PERCENTUALE_SOSPENSIONI_ACQU,'0') PERCENTUALE_SOSPENSIONI_ACQU, NVL(PERC_SOSP_ACQU_CONF,'0') PERC_SOSP_ACQU_CONF,NVL(PERCENTUALE_SUPERAMENTO,'0') PERCENTUALE_SUPERAMENTO FROM (SELECT ROWNUM AS ID, x.* FROM (SELECT COD_DEALER, COD_PDV, TOTAL_ACQUISIZIONI, CONFRONTO_ACQUISIZIONI, CAST( NULL AS NUMBER ) QTA_SOGL, CAST( NULL AS NUMBER ) QTA_SUPE_SOGL, D_RAG_SOC, D_IND, D_LOCALITA, D_CAP, D_PROVINCIA, D_PIVA, INDIRIZZO V_IND, LOCALITA V_LOCALITA, CAP V_CAP, PROVINCIA V_PROVINCIA FROM ANAGRAFICA_DEALER, (SELECT COD_DEALER, COD_PDV, TOTAL_ACQUISIZIONI, CONFRONTO_ACQUISIZIONI, CAST( NULL AS NUMBER ) QTA_SOGL, CAST( NULL AS NUMBER ) QTA_SUPE_SOGL, RAGSOC D_RAG_SOC, INDIRIZZO D_IND, LOCALITA D_LOCALITA, CAP D_CAP, PROVINCIA D_PROVINCIA, PIVA D_PIVA FROM ANAGRAFICA_DEALER, ( SELECT A.COD_DEALER,A.COD_PDV,A.TOTAL_ACQUISIZIONI,NVL(B.TOTAL_ACQUISIZIONI,'0') CONFRONTO_ACQUISIZIONI, CAST( NULL AS NUMBER ) QTA_SOGL, CAST( NULL AS NUMBER ) QTA_SUPE_SOGL FROM (SELECT A.COD_DEALER,A.COD_PDV,COUNT(A.COD_DEALER) TOTAL_ACQUISIZIONI, CAST( NULL AS NUMBER ) QTA_SOGL, CAST( NULL AS NUMBER ) QTA_SUPE_SOGL FROM CFMS_ATT A WHERE A.DATA_ATTIVAZIONE between TO_DATE('2015-06-15 00:00:00','yyyy-mm-dd HH24:MI:SS') AND TO_DATE('2015-06-15 23:59:59','yyyy-mm-dd HH24:MI:SS') AND A.COD_PDV IS NOT NULL GROUP BY A.COD_DEALER,A.COD_PDV) A LEFT JOIN ( SELECT COD_DEALER,COD_PDV,COUNT(COD_DEALER) TOTAL_ACQUISIZIONI FROM CFMS_ATT WHERE DATA_ATTIVAZIONE between TO_DATE('2015-06-16 00:00:00','yyyy-mm-dd HH24:MI:SS') AND TO_DATE('2015-06-16 23:59:59','yyyy-mm-dd HH24:MI:SS') AND COD_PDV IS NOT NULL GROUP BY COD_DEALER,COD_PDV ) B ON A.COD_DEALER=B.COD_DEALER AND A.COD_PDV=B.COD_PDV) WHERE COD_DEALER = COD_ID (+)) WHERE COD_PDV = COD_ID (+) ORDER BY COD_DEALER) x ) A FULL OUTER JOIN (SELECT ROWNUM AS ID, x.* FROM (SELECT COD_DEALER, COD_PDV, ACQUISIZIONI, AVG_ACQUISIZIONI, ACQUISIZIONI_CONFRONTO, AVG_ACQUISIZIONI_CONFRONTO, PERCENTUALE_INCREMENTO, D_RAG_SOC, D_IND, D_LOCALITA, D_CAP, D_PROVINCIA, D_PIVA, INDIRIZZO V_IND, LOCALITA V_LOCALITA, CAP V_CAP, PROVINCIA V_PROVINCIA FROM ANAGRAFICA_DEALER, (SELECT COD_DEALER, COD_PDV, ACQUISIZIONI, AVG_ACQUISIZIONI, ACQUISIZIONI_CONFRONTO, AVG_ACQUISIZIONI_CONFRONTO, PERCENTUALE_INCREMENTO, RAGSOC D_RAG_SOC, INDIRIZZO D_IND, LOCALITA D_LOCALITA, CAP D_CAP, PROVINCIA D_PROVINCIA, PIVA D_PIVA FROM ANAGRAFICA_DEALER, ( SELECT A.COD_DEALER,A.COD_PDV,A.ACQUISIZIONI,TO_CHAR(A.AVG_ACQUISIZIONI,'99990D99')
  • 82. R E A L U S E C A S E - # 2 R E P O R T I N G AS AN analyst I WANT TO request for a new monthly report
  • 83. R E A L U S E C A S E - # 2 R E P O R T I N G AS AN analyst I WANT TO request for a new monthly report SO THAT the system will send me an email with the attached csv report
  • 84. R U N I N B A C K G R O U N D
  • 85. S C A L I N G T H E A S Y N C Y O U R A P P I S H E R E W O R K E R W O R K E R W O R K E R W O R K E R Q U E U E POST /rss PATCH /users POST /export
  • 86. A S Y N C H R O N O U S TA S K • https://github.com/uecode/qpush-bundle • https://github.com/videlalvaro/php-amqplib • https://github.com/videlalvaro/RabbitMqBundle • http://gearmanbundle.readthedocs.org/en/latest/configuration.html • https://github.com/chrisboulton/php-resque
  • 87. T H A N K S