Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge branch 'colored-errors' into wescheme2012-master
- Loading branch information
Showing
238 changed files
with
1,625 additions
and
248 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
We make estimates based on previous usage, in particular blips where | ||
our usage went past free limits. I'm paying about $2.10 a week at the | ||
moment. | ||
|
||
|
||
|
||
According to AppEngine's logs, we do exceed these limits fairly | ||
frequently. Especially on: | ||
|
||
2012-06-20 | ||
2012-06-21 | ||
2012-06-22 | ||
2012-06-14 | ||
|
||
On the week of 6/18-6-22, I paid $2.65. | ||
|
||
|
||
|
||
On those days, the most significant costs were: | ||
|
||
frontend instance hours (around 40 hours) | ||
datastore reads (about half a million read requests) | ||
|
||
Frontend instance hours being high means multiple AppEngine servers | ||
needed to be spun up to support the load at that time, and corresponds | ||
roughly with server load. It contributes the highest amount (70%) of | ||
our costs. Datastore reads cover the next largest chunk of our costs | ||
(28%). | ||
|
||
|
||
On our worst day (2012-06-22), we used $1.19 out of our reserved | ||
$2.00. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
EC2 Auto scaling notes | ||
|
||
|
||
Creating the launch configuration: | ||
|
||
$ as-create-launch-config LaunchConfig-East-20120808 --image-id ami-9fde74f6 --instance-type m1.medium --group quicklaunch-1 --region us-east-1 | ||
$ as-create-launch-config LaunchConfig-West-20120808 --image-id ami-a8038c98 --instance-type m1.medium --group quicklaunch-1 --region us-west-2 | ||
|
||
|
||
|
||
|
||
Creating the auto-scaling groups, attached to a particular load balancer: | ||
|
||
$ as-create-auto-scaling-group WeSchemeCompilerGroup-West --launch-configuration LaunchConfig-West-20120808 --availability-zones us-west-2a --min-size 1 --max-size 10 --load-balancers balanced-wescheme-compilers | ||
|
||
$ as-create-auto-scaling-group WeSchemeCompilerGroup-East --launch-configuration LaunchConfig-East-20120808 --availability-zones us-east-1c --min-size 1 --max-size 10 --load-balancers LoadBalancerEast --region us-east-1 | ||
|
||
|
||
|
||
|
||
Creating the policies for adding a new instances to these group: | ||
|
||
$ as-put-scaling-policy MyScaleUpPolicy --auto-scaling-group WeSchemeCompilerGroup-West --adjustment=1 --type ChangeInCapacity --cooldown 300 --region us-west-2 | ||
|
||
$ as-put-scaling-policy MyScaleUpPolicy --auto-scaling-group WeSchemeCompilerGroup-East --adjustment=1 --type ChangeInCapacity --cooldown 300 --region us-east-1 | ||
|
||
|
||
|
||
Adding a CloudWatch alarm that will trigger this scaling-up policy on high load. 5 minutes at 80% CPU: | ||
|
||
$ mon-put-metric-alarm MyHighCPUAlarm --comparison-operator GreaterThanThreshold --evaluation-periods 1 --metric-name CPUUtilization --namespace "AWS/EC2" --period 300 --statistic Average --threshold 80 --alarm-actions arn:aws:autoscaling:us-west-2:093537034380:scalingPolicy:0c0d1a8a-8828-4395-99ae-8fb35b098e85:autoScalingGroupName/WeSchemeCompilerGroup:policyName/MyScaleUpPolicy --dimensions "AutoScalingGroupName=WeSchemeCompilerGroup" --region us-west-2 | ||
|
||
$ mon-put-metric-alarm MyHighCPUAlarm --comparison-operator GreaterThanThreshold --evaluation-periods 1 --metric-name CPUUtilization --namespace "AWS/EC2" --period 300 --statistic Average --threshold 80 --alarm-actions arn:aws:autoscaling:us-east-1:093537034380:scalingPolicy:62cdf7ae-1d9e-4436-bc77-603c00f63e5f:autoScalingGroupName/WeSchemeCompilerGroup-East:policyName/MyScaleUpPolicy --dimensions "AutoScalingGroupName=WeSchemeCompilerGroup-East" --region us-east-1 | ||
|
||
|
||
|
||
|
||
Creating the other policy for dropping instances: | ||
|
||
$ as-put-scaling-policy MyScaleDownPolicy --auto-scaling-group WeSchemeCompilerGroup-West --adjustment=-1 --type ChangeInCapacity --cooldown 300 --region us-west-2 | ||
|
||
$ as-put-scaling-policy MyScaleDownPolicy --auto-scaling-group WeSchemeCompilerGroup-East --adjustment=-1 --type ChangeInCapacity --cooldown 300 --region us-east-1 | ||
|
||
and adding the corresponding CloudWatch alarms on idleness: | ||
|
||
|
||
$ mon-put-metric-alarm MyLowCPUAlarm --comparison-operator LessThanThreshold --evaluation-periods=1 --metric-name CPUUtilization --namespace "AWS/EC2" --period 300 --statistic Average --threshold 40 --alarm-actions arn:aws:autoscaling:us-west-2:093537034380:scalingPolicy:3a6b57eb-c9c2-4360-8de8-5056b414c66b:autoScalingGroupName/WeSchemeCompilerGroup:policyName/MyScaleDownPolicy --dimensions "AutoScalingGroupName=WeSchemeCompilerGroup" --region us-west-2 | ||
|
||
$ mon-put-metric-alarm MyLowCPUAlarm --comparison-operator LessThanThreshold --evaluation-periods=1 --metric-name CPUUtilization --namespace "AWS/EC2" --period 300 --statistic Average --threshold 40 --alarm-actions arn:aws:autoscaling:us-east-1:093537034380:scalingPolicy:b09438e3-8e77-4e20-9e03-40484c295922:autoScalingGroupName/WeSchemeCompilerGroup-East:policyName/MyScaleDownPolicy --dimensions "AutoScalingGroupName=WeSchemeCompilerGroup-East" --region us-east-1 | ||
|
||
|
||
---------------------------------------------------------------------- | ||
|
||
Changing the launch configuration: | ||
|
||
1. Make sure to add an instance to each load balancer to account for | ||
the disappearance of the auto-scaling group. | ||
|
||
2. Shut down existing instances by updating the max and min size of | ||
the groups down to zero. | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package org.wescheme.data; | ||
|
||
import com.googlecode.objectify.ObjectifyService; | ||
import com.googlecode.objectify.util.DAOBase; | ||
|
||
/** Data Access Object for all the data we're managing with Objectify. | ||
* | ||
* @author dyoo | ||
* | ||
*/ | ||
|
||
public class DAO extends DAOBase { | ||
static { | ||
ObjectifyService.register(Feedback.class); | ||
} | ||
|
||
public void saveFeedback(Feedback feedback) { | ||
ofy().put(feedback); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
package org.wescheme.data; | ||
|
||
import java.util.Date; | ||
|
||
import javax.persistence.Id; | ||
|
||
import org.json.simple.JSONObject; | ||
|
||
import com.googlecode.objectify.annotation.Unindexed; | ||
|
||
|
||
/** Represents feedback we get back from WeScheme users. | ||
* The content is unstructured for the most part; we may want | ||
* to enforce some structure later one to help with data mining. | ||
* @author dyoo | ||
* | ||
*/ | ||
|
||
public class Feedback { | ||
@Id Long id; | ||
@Unindexed String author; | ||
String type; | ||
@Unindexed String feedbackText; | ||
Date date; | ||
|
||
// NoArg constructor for Objectify. | ||
Feedback() {} | ||
|
||
public Feedback(String author, String type, String feedbackText) { | ||
this.author = author; | ||
this.type = type; | ||
this.feedbackText = feedbackText; | ||
this.date = new Date(); | ||
} | ||
|
||
|
||
|
||
public String getAuthor() { return this.author; } | ||
public String getType() { return this.type; } | ||
public String getFeedbackText() { return this.feedbackText; } | ||
|
||
|
||
public JSONObject toJSONObject() { | ||
JSONObject obj = new JSONObject(); | ||
obj.put("id", this.id); | ||
obj.put("author", this.author); | ||
obj.put("type", this.type); | ||
obj.put("feedbackText", this.feedbackText); | ||
// date is represented at amount of milliseconds since the epoch. | ||
obj.put("date", this.date.getTime()); | ||
return obj; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,29 @@ | ||
package org.wescheme.servlet; | ||
|
||
import java.io.IOException; | ||
|
||
import javax.servlet.ServletException; | ||
import javax.servlet.http.HttpServlet; | ||
import javax.servlet.http.HttpServletRequest; | ||
import javax.servlet.http.HttpServletResponse; | ||
|
||
import org.wescheme.data.DAO; | ||
import org.wescheme.data.Feedback; | ||
|
||
public class AddFeedback extends HttpServlet { | ||
/** | ||
* | ||
*/ | ||
private static final long serialVersionUID = -7686196925524722519L; | ||
|
||
public void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { | ||
String author = request.getParameter("author"); | ||
String type = request.getParameter("type"); | ||
String feedbackText = request.getParameter("feedbackText"); | ||
Feedback feedback = new Feedback(author, type, feedbackText); | ||
new DAO().saveFeedback(feedback); | ||
|
||
response.setContentType("text/plain"); | ||
response.getWriter().write("ok"); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,87 @@ | ||
package org.wescheme.servlet; | ||
|
||
import java.io.IOException; | ||
|
||
import javax.servlet.ServletException; | ||
import javax.servlet.http.HttpServlet; | ||
import javax.servlet.http.HttpServletRequest; | ||
import javax.servlet.http.HttpServletResponse; | ||
|
||
import org.json.simple.JSONArray; | ||
import org.json.simple.JSONObject; | ||
import org.wescheme.data.DAO; | ||
import org.wescheme.data.Feedback; | ||
import org.wescheme.user.Session; | ||
import org.wescheme.user.SessionManager; | ||
|
||
import com.google.appengine.api.datastore.Cursor; | ||
import com.google.appengine.api.datastore.QueryResultIterator; | ||
import com.googlecode.objectify.Objectify; | ||
import com.googlecode.objectify.ObjectifyService; | ||
import com.googlecode.objectify.Query; | ||
|
||
/** | ||
* Retrieve all the feedback we get back from users. | ||
* Output is represented as an JSON string: | ||
* { feedbacks: [{ author: string, type: string: feedbackText: string, date: string} ...], | ||
* cursor: string } | ||
* | ||
* The optional "cursor" argument here will allow us to stream | ||
* the table, just in case it gets large enough to hit against | ||
* the compute ceiling enforced by AppEngine. | ||
* | ||
* Only admins should be allowed to get at this information. | ||
* | ||
* This code is adapted from http://code.google.com/p/objectify-appengine/wiki/IntroductionToObjectify | ||
* @author dyoo | ||
* | ||
*/ | ||
public class DumpFeedback extends HttpServlet { | ||
|
||
public static final long LIMIT_MILLIS = 1000 * 25; // provide a little leeway | ||
|
||
|
||
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException, ServletException { | ||
// First, check that the person is admin. | ||
SessionManager sm = new SessionManager(); | ||
Session userSession = sm.authenticate(request, response); | ||
if (!userSession.isAdmin()) { | ||
response.sendError(401); | ||
return; | ||
} | ||
|
||
// Side effect: force loading of the classes. | ||
DAO dao = new DAO(); | ||
|
||
|
||
// Next, start dumping content till we hit CPU limit | ||
long startTime = System.currentTimeMillis(); | ||
Objectify ofy = ObjectifyService.begin(); | ||
Query<Feedback> query = ofy.query(Feedback.class); | ||
String cursorStr = request.getParameter("cursor"); | ||
if (cursorStr != null) { | ||
query.startCursor(Cursor.fromWebSafeString(cursorStr)); | ||
} | ||
|
||
JSONArray listOfFeedbacks = new JSONArray(); | ||
String nextCursorString = null; | ||
|
||
QueryResultIterator<Feedback> iterator = query.iterator(); | ||
while(iterator.hasNext()) { | ||
Feedback feedback = iterator.next(); | ||
listOfFeedbacks.add(feedback.toJSONObject()); | ||
if (System.currentTimeMillis() - startTime > LIMIT_MILLIS) { | ||
nextCursorString = iterator.getCursor().toWebSafeString(); | ||
break; | ||
} | ||
} | ||
|
||
// Finally, dump the content back to the user. | ||
JSONObject result = new JSONObject(); | ||
result.put("feedbacks", listOfFeedbacks); | ||
result.put("cursor", nextCursorString); | ||
response.setContentType("text/plain"); | ||
response.getWriter().write(result.toString()); | ||
} | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.