1

We are currently developing a mobile app for iOS and Android. For this, we need a stable webservices.

Requirements: - Based on PHP and MySQL, must be blazing fast, must be scalable

I've created a custom-coded simple webservices with multiple endpoints to allow passing data from the app to our database, and vice versa.

My Question:

our average response time with my custom coded solution is below 100ms (measured using newrelic) for normal requests (say, updating a DB field, or performing INSERT INTO). This is without any load however (below 100 users daily). When we are creating outbound requests (specifically, sending E-Mail using SendGrid PHP-Framework) we are seeing a response time of > 1000ms. It appears that the request is "waiting" for a response from Sendgrid. Is it possible to tell the script not to "wait for a response"? This is not really ideal. My idea was to store all "pending" requests to a separate table, and then using a cron to run through all "pending" requests and mark them as "completed". Is this a viable solution? And will one cron each minute be enough for processing requests (possible delay of 1min for each E-Mail)?

As always, any replies or suggestions are very appreciated. Thanks in advance!

Camillo
  • 544
  • 1
  • 6
  • 24
  • 1
    You can move the processing of email to the mobile app. You can take advantage of the Obj-c lib and Java lib for a quick integration. – kunal batra Aug 05 '14 at 16:07
  • Hi Kunal, thank you for your reply. We are aware of the libraries for the native app environment. However, we would like to keep all e-mail sending on our webservice's side, as we're using custom dynamic A/B testing in our e-mails (we don't want to re-submit the app if we decide to A/B test an email, as now we can easily change this on our webservices side). Do you know of any way to make the request "non-blocking", meaning, it will just send the request and not wait for any response? Sort of like AJAX / asynchronous requests... I want to apologize, as I am not very experienced in this field. – Camillo Aug 05 '14 at 16:57
  • A way around controlling email content outside of the app (and maintaining consistency amongst apps emails) would be to use [the SendGrid Template Engine](http://sendgrid.com/solutions/email-template-engine) to control email content and then just have your apps tell us (SendGrid) that you want to send your Welcome Email (e.g.) – Nick Q. Aug 05 '14 at 17:07

2 Answers2

7

To answer the first part of your question: Yes you can make asynchronous requests with PHP, and even ignore the service's response. However, as you correctly say it's not a super great solution.

Asynchronous Requests

This excellent blog post on PHP Asynchronous Requests by Segment.io comes to several conclusions:

  • You can open a socket and write to it, as described by this Stack Overflow Topic - However, it seems that this is actually blocking and fairly slow (300ms in their tests).
  • You can write to a log file and then process it in another way (essentially a queue, like you describe) - However, this requires another process to read the log and process it. Using the file system can be slow, and shared files can cause all sorts of problems.
  • You can fork a cURL request - However, this means you aren't waiting for a response, so if SendGrid (or some other service) responds with an error, you can't catch it and react.

Opinion Land

We're now entering semi-opinion land, but queues as you describe (such as a mySQL one with a cron job, or a text file, or something else) tend to be very scalable as you can throw workers at the queue if you need it to process faster. These can be outside your user facing system (and therefor not share resources).

Queues

With a queue, you'd have a separate service that would be responsible for sending an email with SendGrid (e.g.). It would pull tasks off a queue (e.g. "send an email to Nick")and then execute on it.

There are several ways to implement queues that you can process.

  • You can write your own - As you seem to want to stay on PHP/mySQL, if you do this you'll need to take into account a bunch of queueing problems and weird edge cases. However, you'll have absolute control and for a simple application maybe this will work.
  • You can implement a self hosted task queue - Celery is meant to be a distributed task queue, øMQ (ZeroMQ) and RabbitMQ can also be used as Task Queues. These are meant to be fast and distributed and have had a lot of thought put into them. You'd need to benchmark them in your system to see if they speed it up. It'd also mean you have to host additional pieces yourself. This however, is likely to be the fastest solution from a communication standpoint.
  • You can pass things off to a hosted task queue - IronMQ and Amazon SQS are both cool hosted solutions which means you wouldn't need to dedicate resources to them, additionally with IronWorkers (e.g.) you could have the other service taken care of. However, since you're trying to optimize a request to an external service, this probably isn't the solution in this scenario.

Queueing Emails

On the topic of queuing emails (specifically), this is something common to email senders. Like with everything else it means you can have better reliability (because if a service down the line fails you can keep it in the queue and retry).

With email however, there's some specific services out there for queueing messages. These are SMTP Servers. Theoretically you can setup a server like sendmail and then set SendGrid as your "smarthost" or relay and have the server send to SendGrid. It then queues and deals with service interruptions and sends mail with little additional code. However, SMTP servers are pains to deal with, even if they're just forwarding messages. Additionally, SMTP is even slower than HTTP to establish a connection and therefor probably not what you want, but it's good to know.

Community
  • 1
  • 1
Nick Q.
  • 3,947
  • 2
  • 23
  • 37
  • 1
    What a great reply! I'll take some time and look into all resources you've mentioned (the segment.io blog-post looks great as well). Thanks for the time you've put into this, and I'll report back soon if this solved our problem. – Camillo Aug 05 '14 at 17:20
  • We decided to write our own solution in PHP/mySQL which will store all emails in the database in a first step, then a worker will go through the database and process each email one by one. @Nick Q. **Follow up question:** For setting up the worker, we thought about creating a cron that will call the php script which processes emails each minute. Is this a good solution, or is there a better way to schedule the processing of emails? – Camillo Aug 06 '14 at 07:07
  • 1
    A cron job calling a PHP script should be alright, if you're rolling your own it's probably a fairly good solution. – Nick Q. Aug 06 '14 at 17:41
0

Another possible solution if you control your own server environment that will speed up your email sending and your application is to install a mail server such as Postfix locally. You then configure Postfix to use your Sendgrid credentials, so any email sent will go from your server to sendgrid.

This is not a PHP solution, but removes the need for writing your own customer solution. If you set Postfix as the default mail server. You can then just use the php mail() function to send email.

https://sendgrid.com/docs/Integrate/Mail_Servers/postfix.html

Baxny
  • 576
  • 7
  • 12