<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Cheyne Wallace</title>
	<atom:link href="https://www.cheynewallace.com/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.cheynewallace.com</link>
	<description>Developer / Photographer</description>
	<lastBuildDate>Tue, 18 Feb 2020 20:53:05 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=4.7.29</generator>
	<item>
		<title>How To Use Web Sockets (Socket IO) With Digital Ocean Load Balancers And Kubernetes With Ingress Nginx</title>
		<link>https://www.cheynewallace.com/how-to-use-web-sockets-socket-io-with-digital-ocean-load-balancers-and-kubernetes-with-ingress-nginx/</link>
		<comments>https://www.cheynewallace.com/how-to-use-web-sockets-socket-io-with-digital-ocean-load-balancers-and-kubernetes-with-ingress-nginx/#respond</comments>
		<pubDate>Thu, 13 Feb 2020 07:44:49 +0000</pubDate>
		<dc:creator><![CDATA[Cheyne]]></dc:creator>
				<category><![CDATA[Devops]]></category>
		<category><![CDATA[Kubernetes]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[Digital Ocean]]></category>
		<category><![CDATA[Nginx]]></category>

		<guid isPermaLink="false">https://www.cheynewallace.com/?p=423</guid>
		<description><![CDATA[Web sockets are awesome, although it’s not exactly new technology. You would assume that there is a wealth of information out there on the internet covering every possible use case you can imagine however recently I came across a problem that I had assumed would have a heavily documented solution online, but as it turns <a class="more-link" href="https://www.cheynewallace.com/how-to-use-web-sockets-socket-io-with-digital-ocean-load-balancers-and-kubernetes-with-ingress-nginx/">Read More</a>]]></description>
				<content:encoded><![CDATA[<p>Web sockets are awesome, although it’s not exactly new technology. You would assume that there is a wealth of information out there on the internet covering every possible use case you can imagine however recently I came across a problem that I had assumed would have a heavily documented solution online, but as it turns out, I found very little.</p>
<p>The problem I was trying to solve was running a multi server, web socket application (using Socket IO), within Kubernetes on Digital Oceans hosted K8S solution with a Digital Ocean load balancer attached to an Nginx Ingress controller. (That’s ingress-nginx, not nginx’s ingress controller)</p>
<p>This should be fine.. right? Well, there are some tricky gotchas here as I soon discovered that caught me out. I wasted hours tweaking configuration, so i’m writing this blog post so you don’t have to do the same.</p>
<p><span id="more-423"></span></p>
<p>First, the problem and a shameless plug.<br />
We run a dashboard management software product called <a href="https://www.vuepilot.com" target="_blank" data-href="https://www.vuepilot.com"><b>VuePilot</b></a></p>
<figure><img src="https://cdn-images-1.medium.com/max/1600/1*fhzoNJ5rADGAuYEAYwKdlg.jpeg" alt="VuePilot is multiscreen dashboard rotation management software for your work place" data-image-id="1*fhzoNJ5rADGAuYEAYwKdlg.jpeg" data-width="1200" data-height="630" /></figure>
<p>One of the core pieces of functionality VuePilot offers is the ability to remotely manage and control your dashboards and TV screens mounted around your office.</p>
<p>We offer a centralised dashboard that users can use to start, stop, update and configure the dashboard screens in your organisation. Basically allowing you to be lazy and not get out of your seat to update the dashboard screens at the other end of the building.</p>
<p>So, when you click that button to take over a screen and display some new dashboard on it, that happens by way of web sockets. Machines are always online and available for commands from the user at any time.</p>
<p><b>More info</b><br />
<a href="https://www.vuepilot.com/info/how-to-remotely-manage-office-screens" target="_blank"  data-href="https://www.vuepilot.com/info/how-to-remotely-manage-office-screens">How To Remotely Manage Office Dashboard Screens</a><br />
<a href="https://www.vuepilot.com/info/multi-screen-dashboard-management" target="_blank" data-href="https://www.vuepilot.com/info/multi-screen-dashboard-management">How To Manage Multiple Dashboard Screens From One Machine</a></p>
<p>Recently we’ve seen a large uptick in users and have decided to break apart the app and move everything into Kubernetes to offer greater control over our scaling.<br />
For example, the service that handles this remote management behaviour lives as its own service now that purely just handles web socket connections.</p>
<p>So, back to the point of the article, rather than offer a “step by step” guide to setting up load balancers and Kubernetes on Digital Ocean (which would be long) I’m just going to run over the sticking points that you will likely hit when you attempt to do it yourself.</p>
<p>I’d like to point out that if anyone feels like correcting me or pointing out another solution on any of these points, please do so, however this is what worked for me.</p>
<p>Assuming you’ve got your cluster up and running and you’ve configured your ingress-nginx controller of type “LoadBalancer” which has created your Digital Ocean load balancer, what should you be aware of?</p>
<h3>Use HTTP &amp; HTTPS, Not TCP As Load Balancer Protocols</h3>
<p>This one confused me for a while, and I still don’t quite understand why, here’s what I found.</p>
<p>When Kubernetes provisions the load balancer for you, by default the protocol will be set to TCP with the relevant ports (most likely 80 and 443) being routed to the random ports Kubernetes has assigned to the service.</p>
<p>I was unable to get anything working at all with TCP set as the protocol, which is a contrast from how an AWS ELB works whereby it always lists TCP as the protocol and works fine.</p>
<p>Switching to HTTP and HTTPS solved this for me. I suspect playing around with “proxy protocol” may also solve this, but I wasn’t able to get it working for my use case.</p>
<p>Using the HTTPS protocol on the load balancer has the added benefit (if you wish) of offloading TLS / SSL termination at the load balancer level which is not possible when using TCP as the load balancer protocol. You can of course use the SSL Passthrough option if you wish to terminate SSL at the pod level.</p>
<p>You can also do this from the user interface, but you should configure this in your Kubernetes manifests to ensure you can restore this configuration if need be.</p>
<p><strong>Configuring HTTPS</strong></p>
<p>Within your ingress controller service configuration, setting the</p>
<blockquote>
<p style="text-align: left;">service.beta.kubernetes.io/do-loadbalancer-certificate-id</p>
</blockquote>
<p>annotation will automatically switch your TCP 443 routing to be HTTPS 443 by supplying the ID of the certificate you want to use (from Digital Oceans certificate manager).</p>
<p>You can create this certificate from the Digital Ocean dashboard under Account &gt; Security. Annoyingly you need to use doctl with the command</p>
<blockquote>
<p style="text-align: left;">doctl compute certificate list</p>
</blockquote>
<p>to get the certificate ID as its not visible in the dashboard for some reason.</p>
<p><b>Configuring HTTP</b></p>
<p>Within your ingress controller service configuration, setting the</p>
<blockquote>
<p style="text-align: left;">service.beta.kubernetes.io/do-loadbalancer-protocol: http</p>
</blockquote>
<p>annotation will switch your <strong>TCP 80</strong> routing to be <strong>HTTP 80</strong></p>
<p>Here’s an example ingress service config</p>
<pre class="brush: plain; title: ; notranslate">
apiVersion: v1
kind: Service
metadata:
  name: ingress-nginx
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
  annotations:
    service.beta.kubernetes.io/do-loadbalancer-protocol: http
    service.beta.kubernetes.io/do-loadbalancer-tls-ports: &quot;443&quot;
    service.beta.kubernetes.io/do-loadbalancer-redirect-http-to-https: &quot;true&quot;
    # Use &quot;doctl compute certificate list&quot; to get this ID
    service.beta.kubernetes.io/do-loadbalancer-certificate-id: “xxxx-xxxxx-xxxxx”
</pre>
<p>
<strong>Side note:</strong> You do not need to change the TCP settings at the service level for your ingress controller.  Mine still looks like</p>
<pre class="brush: plain; title: ; notranslate">
ports:
  - name: http
    containerPort: 80
    protocol: TCP
  - name: https
    containerPort: 443
    protocol: TCP
</pre>
<h3>Long Life Certificates For CloudFlare Users</h3>
<p>Digital Ocean offers the ability to generate LetsEncrypt certificates for you, providing you host your apps DNS records with them, which is awesome, unless you are using a service like CloudFlare, in which case it sucks because your DNS will be hosted at CloudFlare.<br />
<img src="https://cdn-images-1.medium.com/max/1200/1*wjZA8bIA-bWkmsHcXt42yQ.png" data-image-id="1*wjZA8bIA-bWkmsHcXt42yQ.png" data-width="1200" data-height="408" /></p>
<p>CloudFlare already provides me with managed certificates and well, I’m not going back to managing them myself so how to get around this?</p>
<p>We only need to secure the transmission between CloudFlare and the DO load balancer, the end user will only ever see the CloudFlare certificate so really, we just need a valid cert for secure transport that could even be self signed. Self signed certs however, just don’t feel right, CloudFlare has another option we can use</p>
<p>It’s not completely managed, but CloudFlares Origin CA certificates allow us to generate a certificate, signed by CloudFlare for our domains, with a 15 year expiry which we can then add to Digital Ocean and assign to our load balancer. If you add another domain you will need to regenerate the certificate to include it but this is a pretty simple task.</p>
<p><b>More info here</b><br />
<a href="https://blog.cloudflare.com/cloudflare-ca-encryption-origin/" target="_blank"  data-href="https://blog.cloudflare.com/cloudflare-ca-encryption-origin/">https://blog.cloudflare.com/cloudflare-ca-encryption-origin/</a></p>
<h3>Multi Server “Session ID unknown” Disconnect Errors / Broken Long Polling</h3>
<p>Chances are, you’ll want to run more than one pod serving your Socket IO servers, of which you’ll like use something like Redis as a PubSub backend for communication between the pods. When you do, you’re going to hit one ugly problem.</p>
<figure><img src="https://cdn-images-1.medium.com/max/1200/1*Y8sG2m6zcD-zQL3br8bDYw.jpeg" data-image-id="1*Y8sG2m6zcD-zQL3br8bDYw.jpeg" data-width="812" data-height="381" /></figure>
<p>Your server logs will show your clients repeatedly connecting and disconnecting every few seconds and your client console will be blasted with “Session ID unknown” errors.</p>
<p><b>“What the hell?!”</b> I can hear you say.. Well, that’s the nice version of what I was saying.</p>
<p>This is a result of multiple levels of load balancing at both the DO Load Balancer and the Kubernetes service level balancing you onto different pods.</p>
<p>Socket IO will start by long polling the endpoint, then send a HTTP 101 (Switching Protocols) to “Upgrade” your connection to web sockets. The problem here is that the follow up request doesn’t land on the same pod and so … <b>“Session ID unknown”</b></p>
<p>There are two ways to solve this</p>
<p><b>Solution 1: Use Session Affinity</b></p>
<p>Session affinity essentially means sticky sessions, which basically means, any follow up requests from the same user will be routed to the same pod.</p>
<p>This will allow you to keep using the Long Poll &gt; Upgrade to WS default method for Socket IO.</p>
<p>Just be aware that heavy traffic users making many requests will not be load balanced to other pods, which is fine for web sockets but if you are serving other static content and API requests from the same app, individual users requests will not be spread across your pods which may screw a little with your load balancing strategy.</p>
<p>To this, you simply set the “affinity” annotation at the ingress level. This will set a “route” cookie which contains a hash which nginx remembers that is used to route follow up requests to the same upstream pod.</p>
<p>Here’s an example ingress definition</p>
<pre class="brush: plain; title: ; notranslate">
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: vuepilot-node
  namespace: vuepilot
  annotations:
    nginx.ingress.kubernetes.io/affinity: &quot;cookie&quot;
    nginx.ingress.kubernetes.io/session-cookie-name: &quot;route&quot;
    nginx.ingress.kubernetes.io/session-cookie-hash: &quot;sha1&quot;
    nginx.ingress.kubernetes.io/session-cookie-expires: &quot;172800&quot;
    nginx.ingress.kubernetes.io/session-cookie-max-age: &quot;172800&quot;
</pre>
<p><b>Solution 2: Disable Long Polling</b></p>
<p>You can disable the long polling altogether and go straight to web sockets which prevents this issue whilst not interfering with the natural load balancing. You’ll want to be sure that your users browser will be fine with this before enabling it, as the long poll upgrade is a fairly nice feature of Socket IO and offers a fall back incase of web socket failure.</p>
<p>To do remove long polling and force only web sockets, simply set the transports property in your client to “websocket”</p>
<pre class="brush: jscript; title: ; notranslate">
const ioSocket = io('https://ws.myapp.com', {
  transports: [‘websocket’],
});
</pre>
<h3>Excessive Client Reconnects</h3>
<p>By default our clients will reconnect every 60 seconds as per the default nginx “proxy-read-timeout” configuration. This is pretty excessive so let’s make this something longer, like an hour (3600 seconds).</p>
<figure><img src="https://cdn-images-1.medium.com/max/1600/1*83XQhU1Pnp9C7NzSk5KiSA.jpeg" data-image-id="1*83XQhU1Pnp9C7NzSk5KiSA.jpeg" data-width="660" data-height="220" /></figure>
<p>Again, we can configure this in the ingress annotation definition</p>
<pre class="brush: plain; title: ; notranslate">
 apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: vuepilot-node
  namespace: vuepilot
  annotations:
    nginx.ingress.kubernetes.io/proxy-read-timeout: &quot;3600&quot;
    nginx.ingress.kubernetes.io/proxy-send-timeout: &quot;3600&quot;
</pre>
<h3>Secure Web Sockets (WSS)</h3>
<p>With above protocol changes in place and the load balancer terminating TLS on 443 with our new certificate, we can now force upgrades to WSS instead of WS connections which will be encrypted all the way up to the entry point to our cluster. As mentioned above, you can also use SSL Passthrough if you want to terminate at the pod level.</p>
<p>An example of how you can force WSS from your client side code</p>
<pre class="brush: jscript; title: ; notranslate">
const ioSocket = io(&quot;https://ws.myapp.com&quot;, {
  secure: true,
});
</pre>
<p>The usage of HTTPS in the URL will also tell Socket IO to upgrade to secure transmission.</p>
<h3>Redirecting HTTP To HTTPS</h3>
<p>Rather than do this at the app level we can do this at the load balancer level by setting the</p>
<blockquote>
<p style="text-align: left;">do-loadbalancer-redirect-http-to-https</p>
</blockquote>
<p>annotation to true in our ingress controller service definition.</p>
<p><b>Example</b></p>
<pre class="brush: plain; title: ; notranslate">   
apiVersion: v1
kind: Service
metadata:
  name: ingress-nginx
  namespace: ingress-nginx
labels:
  app.kubernetes.io/name: ingress-nginx
  app.kubernetes.io/part-of: ingress-nginx
annotations:
  service.beta.kubernetes.io/do-loadbalancer-redirect-http-to-https: “true”
</pre>
<h3>Enable CORS</h3>
<p>Depending on your application you’ll possibly want to enable CORS (Cross Origin Resource Sharing) on your ingress to allow clients to connect from other domains.</p>
<p>Again, this is done at the ingress resource level with annotations, here’s an example CORS configuration that essentially opens the ingress to all origins.</p>
<pre class="brush: plain; title: ; notranslate">
apiVersion: extensions/v1beta1
  kind: Ingress
metadata:
  name: vuepilot-node
  namespace: vuepilot
annotations:
  nginx.ingress.kubernetes.io/enable-cors: “true”
  nginx.ingress.kubernetes.io/cors-allow-methods: “PUT, GET, POST, OPTIONS”
  nginx.ingress.kubernetes.io/cors-allow-credentials: “true”
  nginx.ingress.kubernetes.io/configuration-snippet: |
  more_set_headers “Access-Control-Allow-Origin: $http_origin”;
</pre>
<h3>The Final Configuration</h3>
<p>Most of what’s been mentioned above happens in the ingress controller service and ingress resource definitions.<br />
Here’s what the final configuration files look like</p>
<p><b>Ingress Resource</b></p>
<pre class="brush: plain; title: ; notranslate">
apiVersion: extensions/v1beta1
kind: Ingress
metadata:
  name: vuepilot-node
  namespace: vuepilot
  annotations:
    #kubernetes.io/ingress.class: nginx-general
    nginx.ingress.kubernetes.io/affinity: &quot;cookie&quot;
    nginx.ingress.kubernetes.io/session-cookie-name: &quot;route&quot;
    nginx.ingress.kubernetes.io/session-cookie-hash: &quot;sha1&quot;
    nginx.ingress.kubernetes.io/session-cookie-expires: &quot;172800&quot;
    nginx.ingress.kubernetes.io/session-cookie-max-age: &quot;172800&quot;
    nginx.ingress.kubernetes.io/proxy-read-timeout: &quot;3600&quot;
    nginx.ingress.kubernetes.io/proxy-send-timeout: &quot;3600&quot;
    nginx.ingress.kubernetes.io/enable-cors: &quot;true&quot;
    nginx.ingress.kubernetes.io/cors-allow-methods: &quot;PUT, GET, POST, OPTIONS&quot;
    nginx.ingress.kubernetes.io/cors-allow-credentials: &quot;true&quot;
    nginx.ingress.kubernetes.io/configuration-snippet: |
      more_set_headers &quot;Access-Control-Allow-Origin: $http_origin&quot;;
spec:
  rules:
    - host: ws.vuepilot.com
      http:
        paths:
          - path: /
            backend:
              serviceName: vuepilot-node
              servicePort: 8080
</pre>
<p><b>Ingress Controller Service</b></p>
<pre class="brush: plain; title: ; notranslate">
apiVersion: v1
kind: Service
metadata:
  name: ingress-nginx
  namespace: ingress-nginx
  labels:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
  annotations:
    service.beta.kubernetes.io/do-loadbalancer-protocol: http
    service.beta.kubernetes.io/do-loadbalancer-tls-ports: &quot;443&quot;
    service.beta.kubernetes.io/do-loadbalancer-redirect-http-to-https: &quot;true&quot;
    # Use &quot;doctl compute certificate list&quot; to get this ID
    service.beta.kubernetes.io/do-loadbalancer-certificate-id: “xxx-xxx-xxx”
spec:
  type: LoadBalancer
  ports:
    - name: http
      port: 80
      targetPort: 80
    - name: https
      port: 443
      targetPort: 80
  selector:
    app.kubernetes.io/name: ingress-nginx
    app.kubernetes.io/part-of: ingress-nginx
</pre>
<p>Here’s hoping these tips save you some time and hassle <img src="https://s.w.org/images/core/emoji/2.2.1/72x72/1f642.png" alt="🙂" class="wp-smiley" style="height: 1em; max-height: 1em;" /></p>
]]></content:encoded>
			<wfw:commentRss>https://www.cheynewallace.com/how-to-use-web-sockets-socket-io-with-digital-ocean-load-balancers-and-kubernetes-with-ingress-nginx/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Deduplicating Large Data With Rails</title>
		<link>https://www.cheynewallace.com/deduplicating-large-data-with-rails/</link>
		<comments>https://www.cheynewallace.com/deduplicating-large-data-with-rails/#comments</comments>
		<pubDate>Thu, 13 Apr 2017 01:51:47 +0000</pubDate>
		<dc:creator><![CDATA[Cheyne]]></dc:creator>
				<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[deduplication]]></category>
		<category><![CDATA[optimization]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[ruby on rails]]></category>

		<guid isPermaLink="false">http://www.cheynewallace.com/?p=394</guid>
		<description><![CDATA[Storing and retrieving large chunks of data from your database can be tricky if it’s not done correctly. What happens when you want to store a relatively large document or body of text in your database but that large chunk of text is likely to be identical for thousands of new records? You’re faced with <a class="more-link" href="https://www.cheynewallace.com/deduplicating-large-data-with-rails/">Read More</a>]]></description>
				<content:encoded><![CDATA[<p>Storing and retrieving large chunks of data from your database can be tricky if it’s not done correctly.  What happens when you want to store a relatively large document or body of text in your database but that large chunk of text is likely to be identical for thousands of new records?  You’re faced with the possibility of storing gigabytes of duplicated data that really doesn’t need to be there.</p>
<p>At <a href="https://www.vuepilot.com" target="_blank">Vue Pilot</a>, we had this problem a lot. Thousands of duplicate records, with unique IDs but identical content just occupying disk space. It was pretty clear this wasn’t an optimal solution.<br />
<span id="more-394"></span></p>
<p>Here’s the scenario, say you have a piece of software that generates a log file on installation with some key information you would like to track and archive. You push this log file back to your server via an API endpoint and store it in the database. The log file is roughly 100KB in file size, for every 100,000 installs that’s coming close to 10GB in storage.</p>
<p>The problem is 80% of these log files are identical, they contain the same information but we treat and store them as though they were unique, wasting disk space and blowing out our table size and tuple count with an unnecessary number of rows. </p>
<p>We all know disk space is cheap, but processing power isn’t, large tables cause large indexes which in turn cause slower queries, require more CPU cycles and mean you need to be more careful about writing your future SQL queries. If you query on a non-indexed field you can trigger a full table scan and your app takes a big performance hit in the process. </p>
<p>People love to say “<em>storage is cheap! store everything!</em>” but moving, loading and managing 100GB back up files is lot more difficult and time consuming than 20GB backup files, so it’s worth optimizing where possible.</p>
<p>So how do we optimize this? We’re going to create three tables, The user table, one for the log files and one that acts as a join table between the users and logs.  Instead of having a direct relation between the Log and the User, there will be a relation from <strong>User</strong> to the <strong>UserLog</strong> and from the <strong>UserLog</strong> to the <strong>Log</strong>. </p>
<p>Instead of just saving the log file when we receive it, we will instead hash the contents and perform a look up on this hash in the database to see if we have already seen this exact block of data before. If we get a match on the hash we will instead use the id of that record and throw away the data.  This means that if 1000 people generate the exact same log output, we will still only store it once. </p>
<p>Lets have a look at how to set this up</p>
<pre class="brush: ruby; title: Migrations; notranslate">
class CreateLog &lt; ActiveRecord::Migration
  def change
    create_table :log do |t|
      t.string :checksum
      t.text :data
    end

    create_table :user_log do |t|
      t.integer :log_id
      t.integer :user_id
    end

    create_table :users do |t|
      t.string :name
    end

    add_index :logs, :checksum
    add_index :user_logs, :user_id
    add_index :user_logs, :log_id
  end
end
</pre>
<p>Ok so we have the base tables we need to deduplicate our data.  Now lets see how we would store the log files.  (for the sake of a cleaner read, i’m going to omit all the usual boilerplate code you would find in a normal application like validation and authentication and get to the point)</p>
<p>Assuming that we are receiving the logs from an API endpoint somewhere and that we just want to store them for later inspection and return a status code, here is a simple way we could implement it. </p>
<pre class="brush: ruby; title: logs_controller.rb; notranslate">
class LogController &lt; ApplicationController
  def create
    log = Log.store(params[:log_data])
    user_log = UserLog.create(log_id: log.id, user_id: current_user.id)
    render status: 201
  end
end
</pre>
<pre class="brush: ruby; title: user.rb; notranslate">
class User &lt; ActiveRecord::Base
  has_many :logs, through: :user_logs
  has_many :user_logs
end
</pre>
<pre class="brush: ruby; title: user_log.rb; notranslate">
class UserLog &lt; ActiveRecord::Base
  belongs_to :user
  belongs_to :log
end
</pre>
<pre class="brush: ruby; title: log.rb; notranslate">
class Log &lt; ActiveRecord::Base
  has_many :user_logs

  def store(data)
    key = Digest::MD5.hexdigest(data)
    log = Log.find_by_checksum(key)
    if log.nil?
      log = Log.new(data: data, checksum: key)
      Log.transaction(requires_new: true) do
        begin
          log.save!
        rescue ActiveRecord::RecordNotUnique =&gt; e
          raise ActiveRecord::Rollback
        end
      end
    end
    log
  end
end
</pre>
<p>It’s as simple as that. The <strong>Log.store</strong> method simply uses <strong>Digest::MD5.hexdigest</strong> to calculate an MD5 checksum of the log data to which on the next line we then attempt to look up if the record exists.  If it does not, we create a new log file and save it, being sure to wrap the save operation in a transaction just incase another log file with the same content is being stored at the same time. </p>
<p>The User model has a <strong>through: :user_logs</strong> relation to the Log model which means when you call <strong>User.logs</strong> it performs log look up via the smaller join table which just consists of ids in order to find relevant logs. This essentially resolves to a query that looks something like </p>
<pre class="brush: sql; title: ; notranslate">
SELECT * FROM logs 
INNER JOIN user_logs ON logs.id = user_logs.log_id 
WHERE user_logs.user_id = &lt;user_id&gt;
</pre>
<p>As you can see from the following console output, trying to store the same data repeatedly will result in the same record being returned and not repeatedly stored.</p>
<pre class="brush: bash; title: ; notranslate">
2.3.1 :004 &gt; log = &quot;some log file text here&quot;
2.3.1 :005 &gt; Log.store(log).id
 =&gt; 4 
2.3.1 :007 &gt; Log.store(log).id
 =&gt; 4 
2.3.1 :008 &gt; Log.store(log).id
 =&gt; 4 
2.3.1 :009 &gt; Log.store(log).id
 =&gt; 4 
2.3.1 :010 &gt; new_log = &quot;something else&quot;
2.3.1 :011 &gt; Log.store(new_log).id
 =&gt; 5
</pre>
]]></content:encoded>
			<wfw:commentRss>https://www.cheynewallace.com/deduplicating-large-data-with-rails/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Uploading To S3 With AngularJS And Pre-Signed URLs</title>
		<link>https://www.cheynewallace.com/uploading-to-s3-with-angularjs-and-pre-signed-urls/</link>
		<comments>https://www.cheynewallace.com/uploading-to-s3-with-angularjs-and-pre-signed-urls/#comments</comments>
		<pubDate>Thu, 14 Jul 2016 23:10:57 +0000</pubDate>
		<dc:creator><![CDATA[Cheyne]]></dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[angular]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[ruby]]></category>
		<category><![CDATA[ruby on rails]]></category>

		<guid isPermaLink="false">http://www.cheynewallace.com/?p=366</guid>
		<description><![CDATA[This is a revised post based on the popular original article found at Uploading To S3 With AngularJS The content is similar other than a few key steps which have been removed/altered but for the sake of clean reading, I thought I would create a new post for it. Scenario The scenario we’re going to <a class="more-link" href="https://www.cheynewallace.com/uploading-to-s3-with-angularjs-and-pre-signed-urls/">Read More</a>]]></description>
				<content:encoded><![CDATA[<p>This is a revised post based on the popular original article found at <b><a href="http://www.cheynewallace.com/uploading-to-s3-with-angularjs/">Uploading To S3 With AngularJS</a></b><br />
The content is similar other than a few key steps which have been removed/altered but for the sake of clean reading, I thought I would create a new post for it.<br />
<span id="more-366"></span></p>
<h2>Scenario</h2>
<p>The scenario we’re going to build for here will be to upload a file (of any size) directly to AWS S3 into a temporary bucket that we will access using Pre-Signed URLS<br />
The purpose of this front end application will be to get files into AWS S3, using JavaScript and some basic backend code.</p>
<p>A good example is having a user upload a file from a web form for which your application server will then pull back down, encrypt or resize before pushing it back into a more permanent bucket for storage.</p>
<p>By uploading directly to S3 we will be taking load off our application server by not keeping long running connections open while slow clients upload large files. A problem which is especially visible when using services like Heroku.</p>
<h2>Step 1: Add the file directive</h2>
<p>The file directive simply takes the attributes from a file input type and binds it to the <b>$scope.file</b> object so you can easily work with the filename, file size etc from your controllers.</p>
<p>As soon as you select a file, you can access <b>$scope.file.name</b> or <b>$scope.file.size</b> to get the filename and size for handling client side validation and unique S3 object names.</p>
<p>This means you can validate the file size from the browser with something simple like;</p>
<pre class="brush: jscript; title: ; notranslate">
if($scope.file.size &gt; 10585760) {
  alert('Sorry, file size must be under 10MB');
  return false;
}
</pre>
<p>Go ahead and include the following directive in your project;</p>
<pre class="brush: jscript; title: ; notranslate">
directives.directive('file', function() {
  return {
    restrict: 'AE',
    scope: {
      file: '@'
    },
    link: function(scope, el, attrs){
      el.bind('change', function(event){
        var files = event.target.files;
        var file = files[0];
        scope.file = file;
        scope.$parent.file = file;
        scope.$apply();
      });
    }
  };
});
</pre>
<p>In your HTML you will include the file element as follows</p>
<pre class="brush: xml; title: ; notranslate">
&lt;input name=&quot;file&quot; type=&quot;file&quot; file /&gt;
</pre>
<h2>Step 2: Configure CORS And Expiry On The Bucket</h2>
<p>CORS or “<b>Cross Origin Resource Sharing</b>” allows us to restrict the operations that can be performed on a bucket to a specific domain, like your websites domain. Typically a CORS Ajax request will first initiate an <b>OPTIONS</b> HTTP request to the server which will return the allowed options for that endpoint before the real Ajax request actually happens. Think of it like an access request, the server will inspect where the request originated from and return a set of allowed options (or none) for that origin.</p>
<p>Don’t worry, you won’t have to make that request your self, Angular will handle all of that for you, but it&#8217;s good to have a basic understanding of whats happening during the lifetime of the request.</p>
<p><b>Add The CORS Policy</b><br />
From Your AWS console, under S3 click into your bucket then click the Properties button. There you will see a “<b>Add CORS Configuration</b>” button. It&#8217;s here that you&#8217;ll configure your bucket to only allow PUT requests from particular origins.</p>
<p><a href="http://www.cheynewallace.com/wp-content/uploads/2014/08/Screen-Shot-2014-08-15-at-5.11.22-PM.png"><img src="http://www.cheynewallace.com/wp-content/uploads/2014/08/Screen-Shot-2014-08-15-at-5.11.22-PM-1024x173.png" alt="Add CORS" width="690" height="116" class="aligncenter size-large wp-image-335" srcset="https://www.cheynewallace.com/wp-content/uploads/2014/08/Screen-Shot-2014-08-15-at-5.11.22-PM-1024x173.png 1024w, https://www.cheynewallace.com/wp-content/uploads/2014/08/Screen-Shot-2014-08-15-at-5.11.22-PM-300x50.png 300w, https://www.cheynewallace.com/wp-content/uploads/2014/08/Screen-Shot-2014-08-15-at-5.11.22-PM.png 1254w" sizes="(max-width: 690px) 100vw, 690px" /></a></p>
<p>You can use the following sample config &#8211; just edit to reflect your development, production and staging environments.</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;CORSConfiguration xmlns=&quot;http://s3.amazonaws.com/doc/2006-03-01/&quot;&gt;
    &lt;CORSRule&gt;
        &lt;AllowedOrigin&gt;http://localhost:3000&lt;/AllowedOrigin&gt;
        &lt;AllowedOrigin&gt;https://www.yourdomain.com&lt;/AllowedOrigin&gt;
        &lt;AllowedOrigin&gt;http://staging.yourdomain.com&lt;/AllowedOrigin&gt;
        &lt;AllowedMethod&gt;PUT&lt;/AllowedMethod&gt;
        &lt;MaxAgeSeconds&gt;3000&lt;/MaxAgeSeconds&gt;
        &lt;ExposeHeader&gt;x-amz-server-side-encryption&lt;/ExposeHeader&gt;
        &lt;ExposeHeader&gt;x-amz-request-id&lt;/ExposeHeader&gt;
        &lt;ExposeHeader&gt;x-amz-id-2&lt;/ExposeHeader&gt;
        &lt;AllowedHeader&gt;*&lt;/AllowedHeader&gt;
    &lt;/CORSRule&gt;
&lt;/CORSConfiguration&gt;
</pre>
<p>It’s a good idea to split these into other buckets, but for simplicity we’ll just use the one bucket.</p>
<p><b>Configure Object Expiry</b><br />
It&#8217;s a good idea to expire the objects in this bucket after some short period to prevent people from just uploading huge objects to screw with you. Your server side code should handle moving and deleting valid files so you can assume those that are left after 24 hours are not meant to be there. </p>
<p>From your S3 console, view a bucket and then click Properties, expand the &#8220;<b>Lifecycle Rules</b>&#8221; section and follow the prompts.  Set the action to &#8220;Permanently Delete Only&#8221; and set it for 1 day which will delete any objects in the bucket that are older than 1 day permanently. </p>
<p><a href="http://www.cheynewallace.com/wp-content/uploads/2014/08/Screen-Shot-2014-08-15-at-5.03.03-PM.png"><img src="http://www.cheynewallace.com/wp-content/uploads/2014/08/Screen-Shot-2014-08-15-at-5.03.03-PM-1024x208.png" alt="Delete Permanetely" width="690" height="140" class="aligncenter size-large wp-image-332" srcset="https://www.cheynewallace.com/wp-content/uploads/2014/08/Screen-Shot-2014-08-15-at-5.03.03-PM-1024x208.png 1024w, https://www.cheynewallace.com/wp-content/uploads/2014/08/Screen-Shot-2014-08-15-at-5.03.03-PM-300x60.png 300w, https://www.cheynewallace.com/wp-content/uploads/2014/08/Screen-Shot-2014-08-15-at-5.03.03-PM.png 1102w" sizes="(max-width: 690px) 100vw, 690px" /></a></p>
<p>Now you’re ready to lay down some code.</p>
<h2>Step 3: Generate The Pre-Signed URL And Upload</h2>
<p>This is a two step process and assumes you have already configured the AWS SDK credentials on what ever backend framework your using.<br />
First we create a simple function on the server side that generates the URL based on the filename and file type, then we pass that back to the front end for it to push the object to S3 using the Pre-Signed URL as a destination.</p>
<p><b>Generate The URL</b><br />
On the server side you will need to be using the AWS SDK. We&#8217;ll use Ruby for this example. Create a controller action to generate and return the presigned URL as follows</p>
<pre class="brush: ruby; title: ; notranslate">
  def presigned
    if params[:filename] &amp;&amp; params[:type]
      s3 = AWS::S3.new
      obj = s3.buckets[YOUR_TEMP_BUCKET].objects[params[:filename]]
      url = obj.url_for(:write, :content_type =&gt; params[:type], :expires =&gt; 10*60)  # Expires 10 Minutes
      render :json =&gt; {:url =&gt; url.to_s}
    else
      render :json =&gt; {:error =&gt; 'Invalid Params'}
    end
  end
</pre>
<p>The PreSigned URL is dynamic and includes details about the object name, bucket, signature and expiration details. Its important to note that the file name and the content type are included as part of the signature so you need to include them in the front end request to S3 exactly as you did to generate the URL otherwise you&#8217;ll get an invalid signature response. </p>
<p>Now in your Angular controller, create the upload function</p>
<pre class="brush: jscript; title: ; notranslate">
$scope.upload = function(file) {
  // Get The PreSigned URL
  $http.post('/presigned'),{ filename: file.name, type: file.type })
    .success(function(resp) {
      // Perform The Push To S3
      $http.put(resp.url, file, {headers: {'Content-Type': file.type}})
        .success(function(resp) {
          //Finally, We're done
          alert('Upload Done!')
        })
        .error(function(resp) {
          alert(&quot;An Error Occurred Attaching Your File&quot;);
        });
    })
    .error(function(resp) {
      alert(&quot;An Error Occurred Attaching Your File&quot;);
    });
}
</pre>
<p>The <b>$scope.upload</b> method here could be broken out into a service or factory to clean things up a little, but you could also just drop this method into your controller and with a few minor tweaks be up and running.</p>
<h2>Step 4: Processing The Upload</h2>
<p>This step is really going to depend on what you want to do with the file and is going to vary depending on your application server but, generally speaking, now all you need is the path to the file in S3 (which is basically just the bucket name plus the object name) and you can pull the file down, process it and push it back to another location from the server in some sort of background process that doesn&#8217;t tie up the front end.</p>
<p>As an example, in Ruby On Rails, using the AWS SDK for Ruby you could pull the file down, transform it and push it back up to another bucket with something like this</p>
<pre class="brush: ruby; title: ; notranslate">
# Get The Temporary Upload
s3 = AWS::S3.new
temp_obj = s3.buckets['YOUR_TEMP_BUCKET'].objects[params[:uploaded_file]]

begin
  # Read File Size From S3 For Server Size Validation
  size = temp_obj.content_length

  # Assign A Local Temp File
  local_file = &quot;#{Rails.root}/tmp/#{params[:uploaded_file]}&quot;

  # Read In File From S3 To Local Path
  File.open(local_file, 'wb') do |file|
  	temp_obj.read do |chunk|
  		file.write(chunk)
  	end
  end

  #########################################
  # Perform Some Local Transformation Here
  #########################################

  # Now Write Back The Transformed File
  perm_obj = s3.buckets['YOUR_PERMANENT_BUCKET'].objects[params[:uploaded_file]]
  perm_obj.write(File.open(local_file))

  rescue StandardError =&gt; exception
    # That's A Fail
  ensure
    # Delete The Original File
    temp_obj.delete
  end
end
</pre>
<h2>Summary</h2>
<p>We’ve seen now how we can upload files directly to AWS S3 using JavaScript. It may seem like a lot of work from the first few steps in this article, but they are necessary in order to prevent people abusing your S3 bucket and your app.</p>
<p>I&#8217;v been using this technique for a while now and it&#8217;s been pretty solid. It certainly solved my issue with Heroku H12 timeouts which was causing me endless headaches.</p>
<p>Have any suggestions how to improve on this technique? Let me know in the comments section below</p>
]]></content:encoded>
			<wfw:commentRss>https://www.cheynewallace.com/uploading-to-s3-with-angularjs-and-pre-signed-urls/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Uploading To S3 With AngularJS</title>
		<link>https://www.cheynewallace.com/uploading-to-s3-with-angularjs/</link>
		<comments>https://www.cheynewallace.com/uploading-to-s3-with-angularjs/#comments</comments>
		<pubDate>Fri, 15 Aug 2014 04:45:58 +0000</pubDate>
		<dc:creator><![CDATA[Cheyne]]></dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[angularjs]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[heroku]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[s3]]></category>

		<guid isPermaLink="false">http://www.cheynewallace.com/?p=293</guid>
		<description><![CDATA[A little while back I found myself needing to handle file uploads without touching the application server. This is a common scenario for people using Heroku as they limit all requests to 30 seconds, which in theory sounds fine for most requests, but destroys any chance you have at directly handling file uploads within your <a class="more-link" href="https://www.cheynewallace.com/uploading-to-s3-with-angularjs/">Read More</a>]]></description>
				<content:encoded><![CDATA[<p>A little while back I found myself needing to handle file uploads without touching the application server. This is a common scenario for people using Heroku as they limit all requests to 30 seconds, which in theory sounds fine for most requests, but destroys any chance you have at directly handling file uploads within your application.</p>
<p>I restricted my allowed attachment size down to 2MB but still there were people in more remote parts of the world who were hitting that 30 second timeout. Heroku’s response is to simply not upload to the app server and instead go direct to something like AWS S3.<a href="http://www.cheynewallace.com/wp-content/uploads/2014/08/aws.png"><img src="http://www.cheynewallace.com/wp-content/uploads/2014/08/aws.png" alt="aws" width="300" height="300" class="alignright size-full wp-image-330" srcset="https://www.cheynewallace.com/wp-content/uploads/2014/08/aws.png 300w, https://www.cheynewallace.com/wp-content/uploads/2014/08/aws-150x150.png 150w" sizes="(max-width: 300px) 100vw, 300px" /></a></p>
<p>This got me thinking &#8211; can I upload a large file to Amazon S3 using the AWS-JS-SDK with JavaScript and work it into my existing AngularJS application?<span id="more-293"></span></p>
<p>As it turns out, yes you can and just in case you want to jump ahead and skip the blog post, I’ve put up a sample application to demonstrate it along with the full source code here;</p>
<h4 style="margin-bottom: 0;">See A Live Demo Here</h4>
<p><a href="http://cheynewallace.github.io/angular-s3-upload/" target="_blank">http://cheynewallace.github.io/angular-s3-upload/</a></p>
<h4 style="margin-bottom: 0;">Full Source Code And Sample Project Here</h4>
<p><a href="https://github.com/cheynewallace/angular-s3-upload" target="_blank">https://github.com/cheynewallace/angular-s3-upload</a></p>
<h2 style="color: #d73f3f;">UPDATE &#8211; July 14th 2016</h2>
<p>This is been a very popular article for several years now, how ever many people have asked how to avoid using the restricted public keys method shown in this article.  I have created a new post based on this original one that explains how to use Pre-Signed URLs instead. </p>
<p>If you are creating a new public web application you should use this new post as a guide and consider this original one deprecated</p>
<p>Please see<br />
<b><a href="http://www.cheynewallace.com/uploading-to-s3-with-angularjs-and-pre-signed-urls/">Uploading To S3 With AngularJS and Pre-Signed URLs</a></b></p>
<h2>Scenario</h2>
<p>The scenario we’re going to build for here will be to upload a file (of any size) directly to AWS S3 into a temporary bucket that we will access using a restricted and public IAM account.<br />
The purpose of this front end application will be to get files into AWS S3, using only JavaScript libraries from our browser.<br />
We can then kick off a background process with our application server to process these uploaded files at a later time.</p>
<p>A good example of this is having a user upload a file from a web form for which your application server will then pull back down, encrypt or resize before pushing it back into a more permanent bucket for storage.</p>
<p>By uploading directly to S3 we will be taking load off our application server by not keeping long running connections open while slow clients upload large files. A problem which is especially visible when using services like Heroku.</p>
<h2>Step 1: Add The AWS JS SDK To Your Project</h2>
<p>This is Amazons JavaScript SDK and it won’t take long before you notice the file size of this library. It’s pretty obvious that this is more of a backend NodeJS library than a browser JS library, even though they have a “browser” version, it still weighs in at about 230KB.</p>
<p>The easiest way to get this library is to simply “<b>bower install aws-sdk-js</b>” and you’ll get the latest “browser” version.</p>
<p>If you’re already feeling the weight from too many libraries on your app, you can clone the NodeJS repo and compile it your self which I found saved me about 50KB in file size.</p>
<p>More info can be found on the AWS Docs under <a href="http://docs.aws.amazon.com/AWSJavaScriptSDK/guide/browser-building.html" target="_blank">Compiling The AWS SDK</a></p>
<p>You can compile and minify just the S3 component of the SDK from the NodeJS modules using the following command;</p>
<pre class="brush: bash; title: ; notranslate">
MINIFY=1 node dist-tools/browser-builder.js s3 &gt; aws-sdk.min.js
</pre>
<p><a href="https://github.com/cheynewallace/angular-s3-upload/blob/master/components/aws-sdk-custom/aws-sdk.js">You can also just use my compiled custom version found here</a></p>
<h2>Step 2: Add the file directive</h2>
<p>The file directive simply takes the attributes from a file input type and binds it to the <b>$scope.file</b> object so you can easily work with the filename, file size etc from your controllers.</p>
<p>As soon as you select a file, you can access <b>$scope.file.name</b> or <b>$scope.file.size</b> to get the filename and size for handling client side validation and unique S3 object names.</p>
<p>This means you can validate the file size from the browser with something simple like;</p>
<pre class="brush: jscript; title: ; notranslate">
if($scope.file.size &gt; 10585760) {
  alert('Sorry, file size must be under 10MB');
  return false;
}
</pre>
<p>Go ahead and include the following directive in your project;</p>
<pre class="brush: jscript; title: ; notranslate">
directives.directive('file', function() {
  return {
    restrict: 'AE',
    scope: {
      file: '@'
    },
    link: function(scope, el, attrs){
      el.bind('change', function(event){
        var files = event.target.files;
        var file = files[0];
        scope.file = file;
        scope.$parent.file = file;
        scope.$apply();
      });
    }
  };
});
</pre>
<h2>Step 3: Setup The AWS Credentials</h2>
<p>You’re probably wondering how to lock down this new upload functionality considering it’s all JavaScript. There is a few ways you can do this, those being by use of Pre-Signed URL’s or by creating a “public” IAM account.</p>
<p>The use of Pre-Signed URL’s involves making a call to your application server first and retrieving a “pre signed” location for the upload which your server and AWS negotiate on the fly. To keep things simple, we’re not going to use this method today.</p>
<p>The second method, which is the one we’re going to use today is by using a public IAM account, by that I mean a regular IAM account that is heavily restricted to do only 1 particular function, in this case, it will only have permission to PUT files into a particular AWS Bucket and nothing else.</p>
<p>This users API key will be public, so anyone will be able to upload to your bucket if they use this key, which is why we will want to configure the bucket to expire all objects within 24 hours, so even if someone did try and upload a 10 Gigabyte file to screw with you, it would only sit there for a few hours. We will also configure CORS which will prevent people uploading content from anywhere other than your website (more on that later)</p>
<p>Once you upload a file to this temporary bucket from your application, you will want to ping your application server with details of the new file and move it into a new permanent bucket. It’s right here where you will be able to perform any transformations, encryption, resizing or processing.</p>
<p><b>Create The User</b><br />
Go into your AWS console and visit the “<b>Security Credentials</b>” section. Create a new user and call it something like “app_public”. Make sure you download the key information when it is presented, this is what we&#8217;ll be feeding into our app later to upload with.</p>
<p>Under the permissions section, click &#8220;<b>attach a new policy</b>&#8220;, then select the policy generator.<br />
Select Amazon S3 as the service and only select the <b>PutObject</b> action from the drop down list.</p>
<p>The ARN is an Amazon Resource Name. This is going to look like;</p>
<pre class="brush: bash; gutter: false; title: ; notranslate">
arn:aws:s3:::your_bucket_name
</pre>
<p>Click &#8220;<strong>add statement&#8221;</strong>, then save and apply policy. Now your user has write-only access to the bucket.</p>
<p>Your policy is going to look something like this;</p>
<pre class="brush: jscript; title: ; notranslate">
{
  &quot;Version&quot;: &quot;2012-10-17&quot;,
  &quot;Statement&quot;: [
    {
      &quot;Sid&quot;: &quot;Stmt126637111000&quot;,
      &quot;Effect&quot;: &quot;Allow&quot;,
      &quot;Action&quot;: [
        &quot;s3:PutObject&quot;
      ],
      &quot;Resource&quot;: [
        &quot;arn:aws:s3:::your_bucket_name&quot;
      ]
    }
  ]
}
</pre>
<h2>Step 4: Configure CORS And Expiry On The Bucket</h2>
<p>CORS or “<b>Cross Origin Resource Sharing</b>” allows us to restrict the operations that can be performed on a bucket to a specific domain, like your websites domain. Typically a CORS Ajax request will first initiate an <b>OPTIONS</b> HTTP request to the server which will return the allowed options for that endpoint before the real Ajax request actually happens. Think of it like an access request, the server will inspect where the request originated from and return a set of allowed options (or none) for that origin.</p>
<p>Don’t worry, you won’t have to make that request your self, Angular will handle all of that for you, but it&#8217;s good to have a basic understanding of whats happening during the lifetime of the request.</p>
<p><b>Add The CORS Policy</b><br />
From Your AWS console, under S3 click into your bucket then click the Properties button. There you will see a “<b>Add CORS Configuration</b>” button. It&#8217;s here that you&#8217;ll configure your bucket to only allow PUT requests from particular origins.</p>
<p><a href="http://www.cheynewallace.com/wp-content/uploads/2014/08/Screen-Shot-2014-08-15-at-5.11.22-PM.png"><img src="http://www.cheynewallace.com/wp-content/uploads/2014/08/Screen-Shot-2014-08-15-at-5.11.22-PM-1024x173.png" alt="Add CORS" width="690" height="116" class="aligncenter size-large wp-image-335" srcset="https://www.cheynewallace.com/wp-content/uploads/2014/08/Screen-Shot-2014-08-15-at-5.11.22-PM-1024x173.png 1024w, https://www.cheynewallace.com/wp-content/uploads/2014/08/Screen-Shot-2014-08-15-at-5.11.22-PM-300x50.png 300w, https://www.cheynewallace.com/wp-content/uploads/2014/08/Screen-Shot-2014-08-15-at-5.11.22-PM.png 1254w" sizes="(max-width: 690px) 100vw, 690px" /></a></p>
<p>You can use the following sample config &#8211; just edit to reflect your development, production and staging environments.</p>
<pre class="brush: xml; title: ; notranslate">
&lt;?xml version=&quot;1.0&quot; encoding=&quot;UTF-8&quot;?&gt;
&lt;CORSConfiguration xmlns=&quot;http://s3.amazonaws.com/doc/2006-03-01/&quot;&gt;
    &lt;CORSRule&gt;
        &lt;AllowedOrigin&gt;http://localhost:3000&lt;/AllowedOrigin&gt;
        &lt;AllowedOrigin&gt;https://www.yourdomain.com&lt;/AllowedOrigin&gt;
        &lt;AllowedOrigin&gt;http://staging.yourdomain.com&lt;/AllowedOrigin&gt;
        &lt;AllowedMethod&gt;PUT&lt;/AllowedMethod&gt;
        &lt;MaxAgeSeconds&gt;3000&lt;/MaxAgeSeconds&gt;
        &lt;ExposeHeader&gt;x-amz-server-side-encryption&lt;/ExposeHeader&gt;
        &lt;ExposeHeader&gt;x-amz-request-id&lt;/ExposeHeader&gt;
        &lt;ExposeHeader&gt;x-amz-id-2&lt;/ExposeHeader&gt;
        &lt;AllowedHeader&gt;*&lt;/AllowedHeader&gt;
    &lt;/CORSRule&gt;
&lt;/CORSConfiguration&gt;
</pre>
<p>It’s a good idea to split these into other buckets, but for simplicity we’ll just use the one bucket.</p>
<p><b>Configure Object Expiry</b><br />
It&#8217;s a good idea to expire the objects in this bucket after some short period to prevent people from just uploading huge objects to screw with you. Your server side code should handle moving and deleting valid files so you can assume those that are left after 24 hours are not meant to be there. </p>
<p>From your S3 console, view a bucket and then click Properties, expand the &#8220;<b>Lifecycle Rules</b>&#8221; section and follow the prompts.  Set the action to &#8220;Permanently Delete Only&#8221; and set it for 1 day which will delete any objects in the bucket that are older than 1 day permanently. </p>
<p><a href="http://www.cheynewallace.com/wp-content/uploads/2014/08/Screen-Shot-2014-08-15-at-5.03.03-PM.png"><img src="http://www.cheynewallace.com/wp-content/uploads/2014/08/Screen-Shot-2014-08-15-at-5.03.03-PM-1024x208.png" alt="Delete Permanetely" width="690" height="140" class="aligncenter size-large wp-image-332" srcset="https://www.cheynewallace.com/wp-content/uploads/2014/08/Screen-Shot-2014-08-15-at-5.03.03-PM-1024x208.png 1024w, https://www.cheynewallace.com/wp-content/uploads/2014/08/Screen-Shot-2014-08-15-at-5.03.03-PM-300x60.png 300w, https://www.cheynewallace.com/wp-content/uploads/2014/08/Screen-Shot-2014-08-15-at-5.03.03-PM.png 1102w" sizes="(max-width: 690px) 100vw, 690px" /></a></p>
<p>Now you’re ready to lay down some code.</p>
<h2>Step 5: Write Some Angular</h2>
<p>It’s worth mentioning again that there is a <a href="https://github.com/cheynewallace/angular-s3-upload">complete sample application available here</a> that you can pull down and play around with or a <a>live demo application here</a> that you can try out. Simply provide the bucket name, access key and secret access key in the form to upload.</p>
<p>So, if we’ve configured everything mentioned above correctly, we’re ready to see this in action. The following snippet is a simplified version of the sample application I mentioned earlier. It does the basic operations we need to upload a file to S3, which includes:</p>
<ul>
<li>Configure the AWS S3 credentials and bucket object</li>
<li>Check to make sure a file is selected</li>
<li>PUT the object into the S3 bucket whilst displaying progress information to the console</li>
<li>Alert with any errors or config issues.</li>
</ul>
<p>Here&#8217;s what the method in your controller is going to look like</p>
<pre class="brush: jscript; title: ; notranslate">
$scope.creds = {
  bucket: 'your_bucket',
  access_key: 'your_access_key',
  secret_key: 'your_secret_key'
}

$scope.upload = function() {
  // Configure The S3 Object 
  AWS.config.update({ accessKeyId: $scope.creds.access_key, secretAccessKey: $scope.creds.secret_key });
  AWS.config.region = 'us-east-1';
  var bucket = new AWS.S3({ params: { Bucket: $scope.creds.bucket } });

  if($scope.file) {
    var params = { Key: $scope.file.name, ContentType: $scope.file.type, Body: $scope.file, ServerSideEncryption: 'AES256' };

    bucket.putObject(params, function(err, data) {
      if(err) {
        // There Was An Error With Your S3 Config
        alert(err.message);
        return false;
      }
      else {
        // Success!
        alert('Upload Done');
      }
    })
    .on('httpUploadProgress',function(progress) {
          // Log Progress Information
          console.log(Math.round(progress.loaded / progress.total * 100) + '% done');
        });
  }
  else {
    // No File Selected
    alert('No File Selected');
  }
}
</pre>
<p>and the file input element using the file directive</p>
<pre class="brush: xml; title: ; notranslate">
&lt;input name=&quot;file&quot; type=&quot;file&quot; file /&gt;
</pre>
<p>The <b>$scope.upload</b> method here could be broken out into a service or factory to clean things up a little, but you could also just drop this method into your controller and with a few minor tweaks be up and running.</p>
<p>The upload is broken down into parts and uploaded one piece at a time.<br />
The ‘<b>httpUploadProgress</b>’ event is fired after each time a part has finished uploading which is where we can update our progress bars or percentage counters for a more aesthetic UI / UX.<br />
In the snippet above we’re simply logging this to the console, but in the <a href="http://cheynewallace.github.io/angular-s3-upload/" target="_blank">sample application</a> I mentioned earlier i’v used a bootstrap progress bar to indicate the overall progress.</p>
<p><b>Adding Folders</b><br />
If you want to arrange the uploads into folders, you can do this by simply adding the folder name to the end of the bucket name.  So for example, setting <b>$scope.creds.bucket</b> to &#8220;MYBUCKET/user1&#8221; would upload the file into the MYBUCKET bucket under the folder user1. </p>
<p><b>putObject Configuration</b><br />
The putObject params object can hold a lot more configuration than what is shown in this example. Setting content expiry, content type and ACL information is just a few examples of what can be done by adding attributes to the params object.  <a target="_blank" href="http://docs.aws.amazon.com/AWSJavaScriptSDK/latest/AWS/S3.html#putObject-property">You can read more about configuring these here</a></p>
<p>A more comprehensive version of the above code, including file size validation, unique file names and proper notifications can be seen here: <a href="https://github.com/cheynewallace/angular-s3-upload/blob/master/js/controllers.js">https://github.com/cheynewallace/angular-s3-upload/blob/master/js/controllers.js</a></p>
<h2>Step 6: Processing The Upload</h2>
<p>This step is really going to depend on what you want to do with the file and is going to vary depending on your application server but, generally speaking, now all you need is the path to the file in S3 (which is basically just the bucket name plus the object name) and you can pull the file down, process it and push it back to another location from the server in some sort of background process that doesn&#8217;t tie up the front end.</p>
<p>I won&#8217;t expand on this too much as this article was more focused on uploading using purely JavaScript but you can see how we&#8217;re able to POST details of this files new location in S3 fairly easily to the server.</p>
<pre class="brush: jscript; title: ; notranslate">
$scope.s3_path = $scope.creds.bucket + '/' + $scope.file.name;
// mybucket/document.pdf
</pre>
<p>As an example, in Ruby On Rails, using the AWS SDK for Ruby you could pull the file down, transform it and push it back up to another bucket with something like this</p>
<pre class="brush: ruby; title: ; notranslate">
# Get The Temporary Upload
s3 = AWS::S3.new
temp_obj = s3.buckets['YOUR_TEMP_BUCKET'].objects[params[:uploaded_file]]

begin
  # Read File Size From S3 For Server Size Validation
  size = temp_obj.content_length

  # Assign A Local Temp File
  local_file = &quot;#{Rails.root}/tmp/#{params[:uploaded_file]}&quot;

  # Read In File From S3 To Local Path
  File.open(local_file, 'wb') do |file|
  	temp_obj.read do |chunk|
  		file.write(chunk)
  	end
  end

  #########################################
  # Perform Some Local Transformation Here
  #########################################

  # Now Write Back The Transformed File
  perm_obj = s3.buckets['YOUR_PERMANENT_BUCKET'].objects[params[:uploaded_file]]
  perm_obj.write(File.open(local_file))

  rescue StandardError =&gt; exception
    # That's A Fail
  ensure
    # Delete The Original File
    temp_obj.delete
  end
end
</pre>
<h2>Summary</h2>
<p>We’ve seen now how we can upload files directly to AWS S3 using only JavaScript. It may seem like a lot of work from the first few steps in this article, but they are necessary in order to prevent people abusing your S3 bucket and your app so I would avoid creating an open bucket or being lazy with the IAM policy.</p>
<p>I&#8217;v been using this technique for a while now and it&#8217;s been pretty solid. It certainly solved my issue with Heroku H12 timeouts which was causing me endless headaches.</p>
<p>Have any suggestions how to improve on this technique? Let me know in the comments section below</p>
]]></content:encoded>
			<wfw:commentRss>https://www.cheynewallace.com/uploading-to-s3-with-angularjs/feed/</wfw:commentRss>
		<slash:comments>108</slash:comments>
		</item>
		<item>
		<title>Simple Element Toggling With AngularJS</title>
		<link>https://www.cheynewallace.com/simple-element-toggling-with-angular/</link>
		<comments>https://www.cheynewallace.com/simple-element-toggling-with-angular/#respond</comments>
		<pubDate>Tue, 10 Jun 2014 01:24:33 +0000</pubDate>
		<dc:creator><![CDATA[Cheyne]]></dc:creator>
				<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Snips]]></category>

		<guid isPermaLink="false">http://www.cheynewallace.com/?p=276</guid>
		<description><![CDATA[Toggling UI elements is a chore that nobody enjoys. Back when your web apps were primarily jQuery or raw JavaScript you would need to wire up an event handler, catch the click event, determine the current visibility state and switch it. A fairly small job, but still an annoying one when you have a page <a class="more-link" href="https://www.cheynewallace.com/simple-element-toggling-with-angular/">Read More</a>]]></description>
				<content:encoded><![CDATA[<p>Toggling UI elements is a chore that nobody enjoys. Back when your web apps were primarily jQuery or raw JavaScript you would need to wire up an event handler, catch the click event, determine the current visibility state and switch it. A fairly small job, but still an annoying one when you have a page full of these elements.</p>
<p>With Angular you can accomplish this without writing any code, simply by using two HTML attributes.<br />
<span id="more-276"></span></p>
<p>Example, say I want to hide an input box, and have it appear when I click a button, then hide when I click it again.</p>
<pre class="brush: xml; title: ; notranslate">
&lt;a ng-click=&quot;showInput = !showInput&quot;&gt;Toggle Input&lt;/a&gt;
&lt;input type=&quot;text&quot; ng-show=&quot;showInput&quot; /&gt;
</pre>
<p>And that’s all there is to it.</p>
<p>The text input is only being shown when the <strong>$scope.showEmailInput</strong> variable evaluates to true, which of course it doesn’t because it doesn&#8217;t exist yet, so it is hidden.</p>
<p>Once you click the Toggle Email Input button it simply sets the <strong>$scope.showEmailInput</strong> variable to be the inverse of what it currently evaluates to which means it will now become true and the variable will actually exist on the scope now.</p>
<p>This is a super clean way to toggle the visibility of elements without requiring any plumbing code, events or variables to be manually configured on your scope.</p>
]]></content:encoded>
			<wfw:commentRss>https://www.cheynewallace.com/simple-element-toggling-with-angular/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Resend Devise Confirmation Emails For Incomplete Accounts</title>
		<link>https://www.cheynewallace.com/resend-devise-confirmation-emails-for-incomplete/</link>
		<comments>https://www.cheynewallace.com/resend-devise-confirmation-emails-for-incomplete/#comments</comments>
		<pubDate>Fri, 20 Dec 2013 00:37:45 +0000</pubDate>
		<dc:creator><![CDATA[Cheyne]]></dc:creator>
				<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[Snips]]></category>
		<category><![CDATA[heroku]]></category>
		<category><![CDATA[ruby on rails]]></category>

		<guid isPermaLink="false">http://www.cheynewallace.com/?p=256</guid>
		<description><![CDATA[It&#8217;s slightly frustrating looking through your users table and seeing a bunch of accounts that signed up but never confirmed, only existing in this limbo land where you can&#8217;t quite count them as a conversion and they seem to have dropped off the face of the earth. This rake task will look through your users <a class="more-link" href="https://www.cheynewallace.com/resend-devise-confirmation-emails-for-incomplete/">Read More</a>]]></description>
				<content:encoded><![CDATA[<p>It&#8217;s slightly frustrating looking through your users table and seeing a bunch of accounts that signed up but never confirmed, only existing in this limbo land where you can&#8217;t quite count them as a conversion and they seem to have dropped off the face of the earth.</p>
<p>This rake task will look through your users table for unconfirmed devise accounts and one by one resend their confirmation emails.<span id="more-256"></span></p>
<p>You can schedule this to run once a day and attempt to reclaim lost users. Here&#8217;s how</p>
<p>Create a file named &#8220;<b>user.rake</b>&#8221; in your Rails project under <b>lib/tasks</b></p>
<p>Paste the following in</p>
<pre class="brush: ruby; title: ; notranslate">
namespace :user do
  task :resend_confirmation =&gt; :environment do
    users = User.where('confirmation_token IS NOT NULL')
    users.each do |user|
      user.send_confirmation_instructions
    end
  end
end
</pre>
<p>Now from the terminal, from within your Rails app path, simply run</p>
<pre class="brush: bash; title: ; notranslate">
rake user:resend_confirmation
</pre>
<p>or if you&#8217;re a Heroku user</p>
<pre class="brush: bash; title: ; notranslate">
heroku run rake user:resend_confirmation
</pre>
<p>Heroku offers a free scheduler which you can use to schedule the emails to be resent daily. Simply use addon found here: <a href="https://addons.heroku.com/scheduler">https://addons.heroku.com/scheduler</a></p>
]]></content:encoded>
			<wfw:commentRss>https://www.cheynewallace.com/resend-devise-confirmation-emails-for-incomplete/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Using Gravatar With AngularJS</title>
		<link>https://www.cheynewallace.com/using-gravatar-with-angularjs/</link>
		<comments>https://www.cheynewallace.com/using-gravatar-with-angularjs/#comments</comments>
		<pubDate>Fri, 06 Dec 2013 22:16:45 +0000</pubDate>
		<dc:creator><![CDATA[Cheyne]]></dc:creator>
				<category><![CDATA[General]]></category>
		<category><![CDATA[angularjs]]></category>

		<guid isPermaLink="false">http://www.cheynewallace.com/?p=237</guid>
		<description><![CDATA[Want to use Gravatar in your AngularJS app? Use this simple directive to insert Gravatar images in your app. Before you get started, you will need to make sure you have an MD5 hashed version of your users email address. Gravatar uses this hashed version of the email address in order to determine which avatar <a class="more-link" href="https://www.cheynewallace.com/using-gravatar-with-angularjs/">Read More</a>]]></description>
				<content:encoded><![CDATA[<p>Want to use Gravatar in your AngularJS app?<br />
Use this simple directive to insert Gravatar images in your app.</p>
<p>Before you get started, you will need to make sure you have an MD5 hashed version of your users email address. Gravatar uses this hashed version of the email address in order to determine which avatar to display.</p>
<p>It&#8217;s simple in any back end language to generate this hash on page load, or send it down with your JSON model. </p>
<p>In Ruby</p>
<pre class="brush: ruby; title: ; notranslate">
Digest::MD5.hexdigest(email_address)
</pre>
<p>In PHP</p>
<pre class="brush: php; title: ; notranslate">
md5(email_address}
</pre>
<p>Now, Include this directive in your AngularJS application</p>
<pre class="brush: jscript; title: ; notranslate">
 myApp.directive('gravatar', function() {
  return {
    restrict: 'AE',
    replace: true,
    scope: {
      name: '@',
      height: '@',
      width: '@',
      emailHash: '@'
    },
    link: function(scope, el, attr) {
     scope.defaultImage = 'https://somedomain.com/images/avatar.png';
    },
    template: '&lt;img alt=&quot;{{ name }}&quot; height=&quot;{{ height }}&quot;  width=&quot;{{ width }}&quot; src=&quot;https://secure.gravatar.com/avatar/{{ emailHash }}.jpg?s={{ width }}&amp;d={{ defaultImage }}&quot;&gt;'
  };
 });
</pre>
<p>You can change the &#8220;<b>defaultImage</b>&#8221; property to link to a default avatar to display when the user has no Gravatar.</p>
<p>Then simply drop the tag with attributes into your HTML</p>
<pre class="brush: xml; title: ; notranslate">
&lt;span gravatar name=&quot;Bill Murray&quot; width=&quot;50&quot; email-hash=&quot;1726e726ac7163a6f&quot;&gt;&lt;/span&gt;
</pre>
]]></content:encoded>
			<wfw:commentRss>https://www.cheynewallace.com/using-gravatar-with-angularjs/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Serving Compressed Assets With Heroku and Rack-Zippy</title>
		<link>https://www.cheynewallace.com/serving-compressed-assets-with-heroku-rack-zippy/</link>
		<comments>https://www.cheynewallace.com/serving-compressed-assets-with-heroku-rack-zippy/#comments</comments>
		<pubDate>Sun, 29 Sep 2013 20:38:50 +0000</pubDate>
		<dc:creator><![CDATA[Cheyne]]></dc:creator>
				<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[heroku]]></category>
		<category><![CDATA[ruby on rails]]></category>

		<guid isPermaLink="false">http://www.cheynewallace.com/?p=195</guid>
		<description><![CDATA[It&#8217;s often a little known fact that Heroku does by default , NOT serve the compressed version of your assets to the client  browser. Often it&#8217;s all too easy to get lost in the magic that is Heroku slug compilation and the simplicity of a &#8220;git push heroku master&#8221; code deploy that we forget the <a class="more-link" href="https://www.cheynewallace.com/serving-compressed-assets-with-heroku-rack-zippy/">Read More</a>]]></description>
				<content:encoded><![CDATA[<p>It&#8217;s often a little known fact that Heroku does by default , NOT serve the compressed version of your assets to the client  browser.</p>
<p>Often it&#8217;s all too easy to get lost in the magic that is Heroku slug compilation and the simplicity of a &#8220;<em>git push heroku master</em>&#8221; code deploy that we forget the basics of web development and end up serving our clients bloated CSS and JavaScript files, often at ridiculous sizes.</p>
<p>This is especially prominent of late with the rise of the &#8220;do it all&#8221; frameworks like Bootstrap, Foundation, AngularJS, Backbone JS etc.</p>
<p>Chances are, if you use any of these frameworks, you&#8217;re sending hundreds of kilobytes of code down to the browser on every request that is never even used, forcing your users to download the lot each time.<span id="more-195"></span></p>
<p>Heroku states clearly in their<a href="https://devcenter.heroku.com/articles/http-routing#gzipped-responses"> HTTP Routing docs</a>:</p>
<blockquote><p>Since requests to Cedar apps are made directly to the application server – not proxied through an HTTP server like nginx – any compression of responses must be done within your application.</p></blockquote>
<p>So, let&#8217;s see what that looks like to the end user.<br />
<a href="http://www.cheynewallace.com/wp-content/uploads/2013/09/beore.jpg" target="_blank"><img class="aligncenter size-large wp-image-197" alt="before rack-zippy" src="http://www.cheynewallace.com/wp-content/uploads/2013/09/beore-1024x57.jpg" width="690" height="38" srcset="https://www.cheynewallace.com/wp-content/uploads/2013/09/beore-1024x57.jpg 1024w, https://www.cheynewallace.com/wp-content/uploads/2013/09/beore-300x16.jpg 300w, https://www.cheynewallace.com/wp-content/uploads/2013/09/beore.jpg 1200w" sizes="(max-width: 690px) 100vw, 690px" /></a><br />
<strong>File:</strong> application.css<br />
<strong>Size:</strong> 70KB<br />
<strong>Time:</strong> 595ms</p>
<p>Here&#8217;s a typical application.css from a Rails app coming down from Heroku.  We can see that the file was 70KB coming down the wire and took a total of 595ms. (The top figure is the one we&#8217;re interested in)</p>
<p>The fact that the 2 numbers regarding the file size are almost the same means that there is no compression or caching happening.</p>
<p>The top number represents the size of the file downloaded, and the bottom represents the actual size of the file.  In this case the file is 70KB and the client had to download the full 70KB.<br />
Consider how big the standard Bootstrap CSS framework is, together with an accompanying JavaScript MVC framework bundled with your own custom CSS and JS and you can begin to see how this can get out of control.</p>
<p>If we browse the public directory on one of our Heroku Dyno&#8217;s we can see that the compressed version of our assets are there already, pre generated by the assets pre-compilation on your last deploy, they&#8217;re just simply not being served to the browser.</p>
<p><img class="aligncenter size-full wp-image-198" alt="Directory" src="http://www.cheynewallace.com/wp-content/uploads/2013/09/listing.jpg" width="800" height="234" srcset="https://www.cheynewallace.com/wp-content/uploads/2013/09/listing.jpg 800w, https://www.cheynewallace.com/wp-content/uploads/2013/09/listing-300x87.jpg 300w" sizes="(max-width: 800px) 100vw, 800px" /></p>
<h3>Rack-Zippy</h3>
<p>Fortunately, serving these compressed assets is pretty simple with the help of a gem called Rack-Zippy. <a href="https://github.com/eliotsykes/rack-zippy">https://github.com/eliotsykes/rack-zippy</a></p>
<p>Rack zippy is Rack middleware that serves up these compressed assets instead of the full uncompressed version, dramatically improving client download times.</p>
<p>To quote from the github gem page:</p>
<blockquote><p>rack-zippy replaces the ActionDispatch::Static middleware used by Rails, which is not capable of serving the gzipped assets created by the <code>rake assets:precompile</code> task. rack-zippy will serve non-gzipped assets where they are not available or not supported by the requesting client.</p></blockquote>
<p>Installation is simple,</p>
<p>Add to your Gemfile</p>
<pre class="brush: ruby; title: ; notranslate">gem 'rack-zippy'</pre>
<p>Then from the command line</p>
<pre class="brush: bash; title: ; notranslate">bundle install</pre>
<p>Add this line to config/application.rb</p>
<pre class="brush: ruby; title: ; notranslate">config.middleware.swap(ActionDispatch::Static, Rack::Zippy::AssetServer)</pre>
<p>Push to Heroku and you&#8217;re done.<br />
Now let&#8217;s take another look at the file sizes</p>
<p><a href="http://www.cheynewallace.com/wp-content/uploads/2013/09/after-1024x57.jpg" target="_blank"> <img class="aligncenter size-large wp-image-196" alt="After Rack-Zippy" src="http://www.cheynewallace.com/wp-content/uploads/2013/09/after-1024x57.jpg" width="690" height="38" srcset="https://www.cheynewallace.com/wp-content/uploads/2013/09/after-1024x57.jpg 1024w, https://www.cheynewallace.com/wp-content/uploads/2013/09/after-300x16.jpg 300w, https://www.cheynewallace.com/wp-content/uploads/2013/09/after.jpg 1200w" sizes="(max-width: 690px) 100vw, 690px" /> </a><br />
<strong>File:</strong> application.css<br />
<strong>Size:</strong> 12.3KB<br />
<strong>Time:</strong> 180ms</p>
<p>That&#8217;s a pretty drastic improvement. From <strong>70KB</strong> down to <strong>12.3KB</strong>, and this is only taking into account a single CSS file, your JavaScript will also show similar improvements.</p>
<p>So, before you start obsessing over excess code or removing images that enhance the appearance of your website in an attempt to increase client response times, I would first ensure you&#8217;re serving up compressed assets, it&#8217;s probably the easiest thing you can do that yields a performance gain this high.</p>
<p><strong>Other Options<br />
</strong>Another option for serving compressed assets is to modify your config.ru file to use Rack::Deflater.<br />
I have not tested this method, but I hear it&#8217;s also another viable option.<br />
More info can be found here: <a href="http://www.gaurishsharma.com/2012/04/enable-gzip-compression-for-rails-3-2-on-heroku-cedar.html">http://www.gaurishsharma.com/2012/04/enable-gzip-compression-for-rails-3-2-on-heroku-cedar.html</a></p>
]]></content:encoded>
			<wfw:commentRss>https://www.cheynewallace.com/serving-compressed-assets-with-heroku-rack-zippy/feed/</wfw:commentRss>
		<slash:comments>8</slash:comments>
		</item>
		<item>
		<title>Get Active Ports and Associated Process Names In C#</title>
		<link>https://www.cheynewallace.com/get-active-ports-and-associated-process-names-in-c/</link>
		<comments>https://www.cheynewallace.com/get-active-ports-and-associated-process-names-in-c/#comments</comments>
		<pubDate>Sun, 28 Jul 2013 18:57:15 +0000</pubDate>
		<dc:creator><![CDATA[Cheyne]]></dc:creator>
				<category><![CDATA[Snips]]></category>
		<category><![CDATA[C#]]></category>
		<category><![CDATA[Netstat]]></category>

		<guid isPermaLink="false">http://www.cheynewallace.com/?p=168</guid>
		<description><![CDATA[Recently I found myself needing to find a way to determine what open and listening ports along with their associated running processes are currently active on a Windows machine using C#. Some extensive Googling returned pretty dismal results. Retrieving a list of open ports is simple. Retrieving a list of running processes is simple. A <a class="more-link" href="https://www.cheynewallace.com/get-active-ports-and-associated-process-names-in-c/">Read More</a>]]></description>
				<content:encoded><![CDATA[<p>Recently I found myself needing to find a way to determine what open and listening ports along with their associated running processes are currently active on a Windows machine using C#. </p>
<p>Some extensive Googling returned pretty dismal results.  </p>
<p>Retrieving a list of open ports is simple.<br />
Retrieving a list of running processes is simple.<br />
A combination of the two is not.<br />
There were a few external libraries, but it just seemed like overkill for something that should be a pretty simple task.</p>
<p>The solution was to just parse the output of a netstat -a -n -o command. The result from this code snip will return a list of &#8220;Port&#8221; objects which contain process names, port number and protocol as properties.<br />
<span id="more-168"></span></p>
<pre class="brush: csharp; title: ; notranslate">
// ===============================================
// The Method That Parses The NetStat Output
// And Returns A List Of Port Objects
// ===============================================
public static List&lt;Port&gt; GetNetStatPorts()
{
  var Ports = new List&lt;Port&gt;();
 
  try {
    using (Process p = new Process()) {
 
      ProcessStartInfo ps = new ProcessStartInfo();
      ps.Arguments = &quot;-a -n -o&quot;;
      ps.FileName = &quot;netstat.exe&quot;;
      ps.UseShellExecute = false;
      ps.WindowStyle = ProcessWindowStyle.Hidden;
      ps.RedirectStandardInput = true;
      ps.RedirectStandardOutput = true;
      ps.RedirectStandardError = true;
 
      p.StartInfo = ps;
      p.Start();
 
      StreamReader stdOutput = p.StandardOutput;
      StreamReader stdError = p.StandardError;
 
      string content = stdOutput.ReadToEnd() + stdError.ReadToEnd();
      string exitStatus = p.ExitCode.ToString();
      
      if (exitStatus != &quot;0&quot;) {
        // Command Errored. Handle Here If Need Be
      }
 
      //Get The Rows
      string[] rows = Regex.Split(content, &quot;\r\n&quot;);
      foreach (string row in rows) {
        //Split it baby
        string[] tokens = Regex.Split(row, &quot;\\s+&quot;);
        if (tokens.Length &gt; 4 &amp;&amp; (tokens[1].Equals(&quot;UDP&quot;) || tokens[1].Equals(&quot;TCP&quot;))) {
          string localAddress = Regex.Replace(tokens[2], @&quot;\[(.*?)\]&quot;, &quot;1.1.1.1&quot;);
          Ports.Add(new Port {
            protocol = localAddress.Contains(&quot;1.1.1.1&quot;) ? String.Format(&quot;{0}v6&quot;,tokens[1]) : String.Format(&quot;{0}v4&quot;,tokens[1]),
            port_number = localAddress.Split(':')[1],
            process_name = tokens[1] == &quot;UDP&quot; ? LookupProcess(Convert.ToInt16(tokens[4])) : LookupProcess(Convert.ToInt16(tokens[5]))
          });
        }
      }
    }
  } 
  catch (Exception ex) 
  { 
    Console.WriteLine(ex.Message)
  }
  return Ports;
}
 
public static string LookupProcess(int pid) 
{
  string procName;
  try { procName = Process.GetProcessById(pid).ProcessName; } 
  catch (Exception) { procName = &quot;-&quot;;}
  return procName;
}
 
// ===============================================
// The Port Class We're Going To Create A List Of
// ===============================================
public class Port
{
  public string name
  {
    get
    {
      return string.Format(&quot;{0} ({1} port {2})&quot;,this.process_name, this.protocol, this.port_number);
    }
    set { }
  }
  public string port_number { get; set; }
  public string process_name { get; set; }
  public string protocol { get; set; }
}
</pre>
]]></content:encoded>
			<wfw:commentRss>https://www.cheynewallace.com/get-active-ports-and-associated-process-names-in-c/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Heroku Postgres Row Limit Email Notifications</title>
		<link>https://www.cheynewallace.com/heroku-postgres-row-limit-notifications/</link>
		<comments>https://www.cheynewallace.com/heroku-postgres-row-limit-notifications/#respond</comments>
		<pubDate>Tue, 14 May 2013 16:27:50 +0000</pubDate>
		<dc:creator><![CDATA[Cheyne]]></dc:creator>
				<category><![CDATA[Ruby on Rails]]></category>
		<category><![CDATA[Snips]]></category>
		<category><![CDATA[heroku]]></category>
		<category><![CDATA[postgres]]></category>
		<category><![CDATA[ruby on rails]]></category>

		<guid isPermaLink="false">http://www.cheynewallace.com/?p=86</guid>
		<description><![CDATA[So, you&#8217;ve got a side project hosted with Heroku, you only have basic database requirements so the 10,000 row limited Postgres dev plan seems like a good choice and could possibly be a free alternative for a descent amount of time until you need to upgrade. Heck, at $35 a month per dyno, you need <a class="more-link" href="https://www.cheynewallace.com/heroku-postgres-row-limit-notifications/">Read More</a>]]></description>
				<content:encoded><![CDATA[<p>So, you&#8217;ve got a side project hosted with Heroku, you only have basic database requirements so the 10,000 row limited Postgres dev plan seems like a good choice and could possibly be a free alternative for a descent amount of time until you need to upgrade.</p>
<p>Heck, at $35 a month per dyno, you need to try and save some money somewhere, right?</p>
<p>Take for example one of my side projects, it&#8217;s called <a href="https://www.noteshred.com">NoteShred.com</a>. It allows you to send password protected, encrypted notes to people over the internet with a unique URL and have the note automatically destroy its self after it&#8217;s been read.<br />
The beauty of this application is that it is constantly deleting rows from the database every time a note is &#8220;<em>shredded</em>&#8220;, so a 10,000 row count is actually a descent amount of space for this application.</p>
<p>The problem is that 10,000 isn&#8217;t a huge number, and all it takes is one big spike of traffic and you&#8217;ve hit the limit.<br />
Heroku provides a basic alerting service that will tell you once you&#8217;re at 7,000 records and again once you&#8217;ve hit the limit. You will have 24 hours to get your row count back under the limit before you will lose write access to your database. (Thanks to @hgmnz and @ctshryock for pointing this out)<br />
<a href="https://devcenter.heroku.com/articles/heroku-postgres-plans#row-limit-enforcement">More Info Here</a>. </p>
<p>Unfortunately, This is not configurable and the cut off may come at a bad time, say if you&#8217;re on holidays or are not able to dive in and trim back the records before this 24 hour window expires.</p>
<p>The 7,000 row alert is nice how ever not terribly useful for applications like NoteShred where you have a slow creeping database and the difference between 7,000 records and 10,000 records is a large gap in time.<br />
I am most likely going to disregard the 7,000 row alert email because I still have 3,000 left, the next email would be informing me that I have hit the limit and have 24 hours to get it back under control.</p>
<p>A configurable threshold with a series of alerts leading up to the cut off point would be more useful, or even just an alert closer to the limit, say at 9000 rows.</p>
<p>You want to keep an eye on this row count, you can do so using the Rails built in Mailer and a basic Rake task with this simple solution and be alerted when your application reaches a threshold nearing that 10,000 mark. You can easily customize this rake task to alert you at times when feel it&#8217;s more useful than the standard 7,000 and 10,000 alerts.</p>
<p>In a nutshell, this will:</p>
<ol>
<li><span style="line-height: 15px;">Check your row count every hour</span></li>
<li>Email you if you&#8217;re over the threshold</li>
</ol>
<p><span id="more-86"></span></p>
<div class="content-title">Step 1: Create A Rake Task</div>
<p>In your Rails application, under the folder <b>/lib/tasks/</b> create the file <b>report.rake</b></p>
<p>Enter the following</p>
<pre class="brush: ruby; title: ; notranslate">
namespace :report do
  task :heroku_row_report =&gt; :environment do
    #Send Warning Email If Over The 9000 Threshold
    warning_threshold = 9000
    query = 'select sum(n_live_tup) as records from pg_stat_user_tables'
    record_count = ActiveRecord::Base.connection.execute(query)[0]['records'].to_i
    if record_count &gt; warning_threshold
      puts &quot;Uh Oh .. We're Up To #{record_count} Records&quot;
      Mailer.heroku_row_report(record_count.to_s).deliver
    else
      puts &quot;We Cool, Only #{record_count} Records&quot;
    end
  end
end
</pre>
<p>Simply change the</p>
<pre class="brush: ruby; light: true; title: ; notranslate">warning_threshold = 9000</pre>
<p>part to what ever number you want to be alerted at</p>
<div class="content-title">Step 2: Create The Mailer Action and View</div>
<p>You will need an action in your Mailer that will send you the email if the rake task discovers your row count is over the threshold.<br />
Add the following to your Mailer class (<em>/app/mailers/mailer.rb</em>)</p>
<pre class="brush: ruby; title: ; notranslate">
def heroku_row_report(rows)
  @rows = rows
  mail :to =&gt; &quot;your_email@domain.com&quot;, :subject =&gt; &quot;Heroku Row Report&quot;
end
</pre>
<p>Now add the view (<em>/app/views/mailer/heroku_row_report.html.erb</em>)</p>
<pre class="brush: xml; title: ; notranslate">
&lt;h3&gt;Heroku Row Count Warning&lt;/h3&gt;
Your Heroku Row Count Is At: &lt;%= @rows %&gt;
</pre>
<p>Obviously you can substitute the above mailer action and view with a custom one of your choosing.</p>
<div class="content-title">Step 3: Test The Rake Task</div>
<p>At this point, let&#8217;s test the rake task.<br />
Open up your console and change into your Rails application directory, then run:</p>
<pre class="brush: bash; title: ; notranslate">
heroku run rake report:heroku_row_report
</pre>
<p>You should see a response on the screen that looks like the following:</p>
<p><img class="aligncenter size-large wp-image-104" alt="Heroku Postgres Row Count" src="http://www.cheynewallace.com/wp-content/uploads/2013/05/Screen-Shot-2013-05-13-at-11.12.37-PM-1024x599.png" width="690" height="403" srcset="https://www.cheynewallace.com/wp-content/uploads/2013/05/Screen-Shot-2013-05-13-at-11.12.37-PM-1024x599.png 1024w, https://www.cheynewallace.com/wp-content/uploads/2013/05/Screen-Shot-2013-05-13-at-11.12.37-PM-300x175.png 300w, https://www.cheynewallace.com/wp-content/uploads/2013/05/Screen-Shot-2013-05-13-at-11.12.37-PM.png 1550w" sizes="(max-width: 690px) 100vw, 690px" /></p>
<p>Remember, you will only be emailed if the row count exceeds the threshold you set earlier, so in the case of my screenshot, I would not be emailed.</p>
<p>If you wanted to get an email all the time, a simple way to do this is to change the threshold to 0.</p>
<div class="content-title">Step 4: Schedule The Rake Task</div>
<p>You&#8217;ll want this rake task to run every hour or so. This is simple to do with the free Heroku Scheduler found here: <a href="https://addons.heroku.com/scheduler">https://addons.heroku.com/scheduler</a>.</p>
<p>Simply add the Heroku Scheduler add-on to your project, jump into the scheduler dashboard, create a new job and enter</p>
<pre class="brush: plain; title: ; notranslate">
rake report:heroku_row_report
</pre>
<p>as the task to run.</p>
<p>Set the job to run every 1 hour, daily, and you&#8217;re done</p>
<p><a href="http://www.cheynewallace.com/wp-content/uploads/2013/05/Screen-Shot-2013-05-13-at-11.27.07-PM.png"><img class="aligncenter size-large wp-image-112" alt="Heroku Scheduler" src="http://www.cheynewallace.com/wp-content/uploads/2013/05/Screen-Shot-2013-05-13-at-11.27.07-PM-1024x379.png" width="690" height="255" srcset="https://www.cheynewallace.com/wp-content/uploads/2013/05/Screen-Shot-2013-05-13-at-11.27.07-PM-1024x379.png 1024w, https://www.cheynewallace.com/wp-content/uploads/2013/05/Screen-Shot-2013-05-13-at-11.27.07-PM-300x111.png 300w, https://www.cheynewallace.com/wp-content/uploads/2013/05/Screen-Shot-2013-05-13-at-11.27.07-PM.png 1544w" sizes="(max-width: 690px) 100vw, 690px" /></a></p>
]]></content:encoded>
			<wfw:commentRss>https://www.cheynewallace.com/heroku-postgres-row-limit-notifications/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
