<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: juanc4milo</title>
    <description>The latest articles on DEV Community by juanc4milo (@juanc4milo).</description>
    <link>https://dev.to/juanc4milo</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F498868%2F36334c4b-0720-4fb3-ac65-060e3e1c9d6d.png</url>
      <title>DEV Community: juanc4milo</title>
      <link>https://dev.to/juanc4milo</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/juanc4milo"/>
    <language>en</language>
    <item>
      <title>Using StringJoiner in Java</title>
      <dc:creator>juanc4milo</dc:creator>
      <pubDate>Sat, 14 Nov 2020 14:03:51 +0000</pubDate>
      <link>https://dev.to/juanc4milo/using-stringjoiner-in-java-3m0j</link>
      <guid>https://dev.to/juanc4milo/using-stringjoiner-in-java-3m0j</guid>
      <description>&lt;h2&gt;
  
  
  What is StringJoiner?
&lt;/h2&gt;

&lt;p&gt;The StringJoiner class in Java 8 is one of the new classes that we can find in this version of Java. Many new features were included in Java 8 and one of them could be this new class. What is StringJoiner for? It is used to merge a set of strings with a delimiter in a very simple way.&lt;/p&gt;

&lt;p&gt;An example of how to use StringJoiner would be the following:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;dev.juanc4milo&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.ArrayList&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.List&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.StringJoiner&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/**
 *
 * @author juanc4milo
 */&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TestStringJoiner&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
    &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;firstSetWords&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;

    &lt;span class="n"&gt;firstSetWords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"this"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;firstSetWords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"is"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;firstSetWords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;firstSetWords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;firstSetWords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"with"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;firstSetWords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"stringjoiner"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;firstSetWords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"in"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;firstSetWords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"java8"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="nc"&gt;StringJoiner&lt;/span&gt; &lt;span class="n"&gt;groupingFirstSetOfWords&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;StringJoiner&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;","&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;firstSetWords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;forEach&lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;groupingFirstSetOfWords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;});&lt;/span&gt;

    &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;groupingFirstSetOfWords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In output console you would see:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Output: &lt;br&gt;&lt;br&gt;
this,is,a,test,with,stringjoiner,in,java8&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  StringJoiner - String delimited by prefix and sufix
&lt;/h2&gt;

&lt;p&gt;In the above example, a string set was grouped as a single string separated by a delimiter (comma). With StringJoiner it can also be initialized by defining a prefix and a suffix. That is one character at the beginning of the string and another character at the end of the string. To do this, in the constructor class you must say what the prefix and suffix will be.&lt;/p&gt;

&lt;p&gt;Let's see this in the following lines of code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;StringJoiner&lt;/span&gt; &lt;span class="n"&gt;groupingFirstSetOfWords&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;StringJoiner&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;","&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"["&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"]"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;firstSetWords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;forEach&lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;groupingFirstSetOfWords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;});&lt;/span&gt;

    &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;groupingFirstSetOfWords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the output console would see:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Output: &lt;br&gt;&lt;br&gt;
[this,is,a,test,with,stringjoiner,in,java8]&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Merging StringJoiners
&lt;/h2&gt;

&lt;p&gt;You can also concatenate two StringJoiner to form a large single string set of text using the &lt;em&gt;merge&lt;/em&gt; method. &lt;/p&gt;

&lt;p&gt;Keep in mind that if you use delimiters, the delimiter of whoever performs the &lt;em&gt;merge&lt;/em&gt; function prevails:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="kn"&gt;package&lt;/span&gt; &lt;span class="nn"&gt;dev.juanc4milo&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.ArrayList&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.List&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;
&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="nn"&gt;java.util.StringJoiner&lt;/span&gt;&lt;span class="o"&gt;;&lt;/span&gt;

&lt;span class="cm"&gt;/**
 *
 * @author juanc4milo
 */&lt;/span&gt;
&lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;TestStringJoiner&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;

    &lt;span class="kd"&gt;public&lt;/span&gt; &lt;span class="kd"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; 
    &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;firstSetWords&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;

    &lt;span class="n"&gt;firstSetWords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"this"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;firstSetWords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"is"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;firstSetWords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"a"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;firstSetWords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"test"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;firstSetWords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"with"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;firstSetWords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"stringjoiner"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;firstSetWords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"in"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;firstSetWords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"java8"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="nc"&gt;StringJoiner&lt;/span&gt; &lt;span class="n"&gt;groupingFirstSetOfWords&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;StringJoiner&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;","&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"["&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"]"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;firstSetWords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;forEach&lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;groupingFirstSetOfWords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;});&lt;/span&gt;

    &lt;span class="nc"&gt;List&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;lastSetWords&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;ArrayList&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&amp;gt;();&lt;/span&gt;

    &lt;span class="n"&gt;lastSetWords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Enjoy"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;lastSetWords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"this"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;lastSetWords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"blog post"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="nc"&gt;StringJoiner&lt;/span&gt; &lt;span class="n"&gt;groupingLastSetOfWords&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;StringJoiner&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="s"&gt;","&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"{"&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt;&lt;span class="s"&gt;"}"&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="n"&gt;lastSetWords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;forEach&lt;/span&gt;&lt;span class="o"&gt;((&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;groupingLastSetOfWords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;add&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;string&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
        &lt;span class="o"&gt;});&lt;/span&gt;

    &lt;span class="n"&gt;groupingLastSetOfWords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;merge&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;groupingFirstSetOfWords&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;

    &lt;span class="nc"&gt;System&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;out&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;println&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;groupingLastSetOfWords&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;toString&lt;/span&gt;&lt;span class="o"&gt;());&lt;/span&gt;
  &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the output console would see:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Output: &lt;br&gt;&lt;br&gt;
{Enjoy,this,blog post,this,is,a,test,with,stringjoiner,in,java8}&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  Thank you for reading, and let's connect!
&lt;/h4&gt;

&lt;p&gt;Thank you for reading my blog. Feel free to follow me and check out &lt;a href="https://juanc4milo.dev"&gt;my webpage&lt;/a&gt; to subscribe to my email newsletter.&lt;/p&gt;

&lt;h3&gt;
  
  
  Other articles that you might like...
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/redis-instalacion-y-configuracion"&gt;Redis - Instalación y Configuración&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/aws-s3-batch-operations"&gt;AWS S3 Batch Operations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/inventario-aws-s3"&gt;AWS S3 Inventory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/aws-elasticache"&gt;Qué ofrece y cómo se configura AWS Elasticache?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/aws-elasticache"&gt;Qué ofrece y cómo se configura Elasticache en AWS?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt; &lt;a href="https://juanc4milo.dev/redis-with-spring-in-java"&gt;How to use Redis with Spring in Java&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/send-email-with-aws-and-track-events"&gt;How to send an email with AWS SES and track events with Configuration Sets?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/receive-emails-in-s3-with-aws-ses"&gt;How to receive emails in a S3 bucket with AWS SES?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/add-sold-out-badge-product-using-woocommerce"&gt;How to add a Sold Out snippet or badge on a particular product using Woocommerce?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Do you like it?&lt;/strong&gt; You can &lt;a href="https://buymeacoffee.com/juanc4milo"&gt;buy me a beer&lt;/a&gt; if you want.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://juanc4milo.dev"&gt;juanc4milo.dev&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>java</category>
      <category>string</category>
    </item>
    <item>
      <title>How to add a Sold Out snippet or badge on a particular product using Woocommerce?</title>
      <dc:creator>juanc4milo</dc:creator>
      <pubDate>Fri, 13 Nov 2020 17:11:08 +0000</pubDate>
      <link>https://dev.to/juanc4milo/how-to-add-a-sold-out-snippet-or-badge-on-a-particular-product-using-woocommerce-51gc</link>
      <guid>https://dev.to/juanc4milo/how-to-add-a-sold-out-snippet-or-badge-on-a-particular-product-using-woocommerce-51gc</guid>
      <description>&lt;p&gt;This article is based on the description of how it would help solve a problem that I have encountered before related to the task ✍️ that @&lt;a href="https://dev.to@dailydevtips"&gt;Chris Bongers&lt;/a&gt; left in &lt;strong&gt;Hashnode Bootcamp-II&lt;/strong&gt; ⛺.&lt;/p&gt;

&lt;p&gt;If you are setting up a Wordpress site with Woocommerce, notice when any product inventory is out of stock, there is nothing on the item catalog page to help you determine the product's stock availability.&lt;/p&gt;

&lt;p&gt;For the customer it is annoying to click every product to see the stock availability.&lt;/p&gt;

&lt;p&gt;To deal with that, there are 2 options that can help you :&lt;/p&gt;

&lt;h2&gt;
  
  
  ✅ Function in PHP
&lt;/h2&gt;

&lt;p&gt;In the * functions.php * file normally found in the Theme folder, insert the following code at the end of the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight php"&gt;&lt;code&gt;&lt;span class="nf"&gt;add_action&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'woocommerce_after_shop_loop_item_title'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'talbiconsept_wc_template_loop_stock'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;function&lt;/span&gt; &lt;span class="n"&gt;talbiconsept_wc_template_loop_stock&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;product&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="k"&gt;global&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;stock&lt;/span&gt; &lt;span class="nf"&gt;management&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="err"&gt;$&lt;/span&gt; &lt;span class="n"&gt;product&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;get_stock_quantity&lt;/span&gt; &lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;echo&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;p class = "stock out of stock"&amp;gt;'&lt;/span&gt; &lt;span class="mf"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;__&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Sold out!'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="mf"&gt;.&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;/p&amp;gt;'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  ✅ Add a plugin
&lt;/h2&gt;

&lt;p&gt;In Wordpress Admin Desktop, go to the Plugins tab and look for "&lt;em&gt;Out of Stock Badge for WooCommerce&lt;/em&gt;":&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FARyPBi7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1605201657715/40YPt4Re1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FARyPBi7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1605201657715/40YPt4Re1.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then go to plugin settings and set text label, font size, font color, and background color:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QaybgQoQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1605201897944/XNuDmFuH5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QaybgQoQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1605201897944/XNuDmFuH5.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;And that is! 😎&lt;/p&gt;

&lt;h3&gt;
  
  
  Other articles that you might like...
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/redis-instalacion-y-configuracion"&gt;Redis - Instalación y Configuración&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/aws-s3-batch-operations"&gt;AWS S3 Batch Operations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/inventario-aws-s3"&gt;AWS S3 Inventory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/aws-elasticache"&gt;Qué ofrece y cómo se configura AWS Elasticache?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/aws-elasticache"&gt;Qué ofrece y cómo se configura Elasticache en AWS?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt; &lt;a href="https://juanc4milo.dev/redis-with-spring-in-java"&gt;How to use Redis with Spring in Java&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/send-email-with-aws-and-track-events"&gt;How to send an email with AWS SES and track events with Configuration Sets?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/receive-emails-in-s3-with-aws-ses"&gt;How to receive emails in a S3 bucket with AWS SES?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Do you like it?&lt;/strong&gt; You can &lt;a href="https://buymeacoffee.com/juanc4milo"&gt;buy me a beer&lt;/a&gt; if you want.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://juanc4milo.dev"&gt;juanc4milo.dev&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>wordpress</category>
      <category>woocommerce</category>
      <category>php</category>
    </item>
    <item>
      <title>How to receive emails in a S3 bucket with AWS SES?</title>
      <dc:creator>juanc4milo</dc:creator>
      <pubDate>Sat, 07 Nov 2020 20:52:16 +0000</pubDate>
      <link>https://dev.to/juanc4milo/how-to-receive-emails-in-a-s3-bucket-with-aws-ses-mn6</link>
      <guid>https://dev.to/juanc4milo/how-to-receive-emails-in-a-s3-bucket-with-aws-ses-mn6</guid>
      <description>&lt;p&gt;If you want to receive your emails in an S3 bucket, this is the tutorial you should follow.&lt;/p&gt;

&lt;h2&gt;
  
  
  Prerequisite: Configure an AWS S3 Bucket
&lt;/h2&gt;

&lt;p&gt;You must create an S3 bucket where the emails are going to deposit.&lt;/p&gt;

&lt;p&gt;To do this, create a standard bucket type and assign a policy that Amazon SES can write the files to it. The policy must be like the following:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Version"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"2012-10-17"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"Statement"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Sid"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"AllowSESPuts"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Effect"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Allow"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Principal"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"Service"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"ses.amazonaws.com"&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Action"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"s3:PutObject"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Resource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"arn:aws:s3:::bucket-name/*"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="nl"&gt;"Condition"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="nl"&gt;"StringEquals"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
                    &lt;/span&gt;&lt;span class="nl"&gt;"aws:Referer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"your-account-ID"&lt;/span&gt;&lt;span class="w"&gt;
                &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
            &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;



&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Configuration in Amazon SES
&lt;/h2&gt;
&lt;h3&gt;
  
  
  Verify a domain
&lt;/h3&gt;

&lt;p&gt;Enter the domain that the email account belongs to so that Amazon can verify that the domain is yours. To do this, enter the Domains section and enter the domain:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604518525966%2FcWSnzr7ww.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604518525966%2FcWSnzr7ww.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;On the DNS settings you own (Godaddy, Hostgator, Route53, etc.), you must create and enter the verification record sets that Amazon delivers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604518890563%2FYBjGDDb0f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604518890563%2FYBjGDDb0f.png" alt="image.png"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604519317424%2F-8HYWbL8V.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604519317424%2F-8HYWbL8V.png" alt="image.png"&gt;&lt;/a&gt; &lt;/p&gt;

&lt;p&gt;Amazon must verify the domain, so you must enter this information in DNS settings. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;If you are using Cloudfare or any CDN, you must enter these settings too.&lt;/em&gt; &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Just wait 5 minutes to propagate the changes around the DNSs... &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604519522061%2FZaBh-DAcX.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604519522061%2FZaBh-DAcX.png" alt="image.png"&gt;&lt;/a&gt; &lt;/p&gt;
&lt;h3&gt;
  
  
  Set Up an MX record in your DNS Settings
&lt;/h3&gt;

&lt;p&gt;A mail exchange record (MX record) is a setting that specifies the mail servers that can accept email sent to your domain.&lt;/p&gt;

&lt;p&gt;To add an MX record to your domain's DNS settings, you must do the following: &lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Log in to the DNS provider management console.&lt;/li&gt;
&lt;li&gt;Create a new MX record.&lt;/li&gt;
&lt;li&gt;In the Name field of the MX record, specify the domain followed by a period. Example: mydomain.com.&lt;/li&gt;
&lt;li&gt;For Type, select MX.&lt;/li&gt;
&lt;li&gt;In Value, enter the following:&lt;/li&gt;
&lt;/ul&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

inbound-smtp.regionInboundUrl.amazonaws.com


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;For example, if you are using the US East (N. Virginia) region, replace the region with us-east-1. It should be:&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&lt;p&gt;inbound-smtp.us-east-1.amazonaws.com&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Create a Receive Rule Set&lt;br&gt;
&lt;/h3&gt;

&lt;p&gt;To create a set of rules in Amazon SES, go to the Rule Sets section and click on the Create a Rule Set button:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604636078121%2FoyTBJiMjt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604636078121%2FoyTBJiMjt.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Specify the email account or domain from where you want to receive emails. If none is specified, you will receive emails from all accounts: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604636096531%2FC_PvDMSFj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604636096531%2FC_PvDMSFj.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select an action, of type S3:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604636113335%2FenOBqh1D4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604636113335%2FenOBqh1D4.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In the action configuration, select the name of the bucket, and say the prefix to save the files (path in S3):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604636134859%2F8_Y_uQaA_.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604636134859%2F8_Y_uQaA_.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Specify a rule name, enable it and check "Enable spam and virus scanning" if you want AWS to scan the emails: &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604636588954%2FHQblYP88-.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604636588954%2FHQblYP88-.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Review your configuration:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604636756670%2Fe5R6Jhiht.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604636756670%2Fe5R6Jhiht.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you hit the save button, the Rule set is created and AWS sends a notification file to the prefix bucket. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604636822621%2FBkm-eS3h0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604636822621%2FBkm-eS3h0.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can download it and add a &lt;em&gt;.EML&lt;/em&gt; extension to open with Outlook or any email application and read the AWS setup notification.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604636954982%2FJ8nbMWTVV.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604636954982%2FJ8nbMWTVV.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Test
&lt;/h2&gt;

&lt;p&gt;Login into your preferred mailbox account and send an email to the recipient that you specified in the Rule Set condition:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604637067677%2FrRwj7Mb3l.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604637067677%2FrRwj7Mb3l.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After you send the email, check the S3 and you should receive an email file. You can download it and add the extension &lt;em&gt;.EML&lt;/em&gt; to open it. &lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604637133327%2FC9GFcvOeX.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604637133327%2FC9GFcvOeX.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Finally...
&lt;/h2&gt;

&lt;p&gt;At this point, you can integrate your Cloud Applications with AWS S3 to process your emails.&lt;/p&gt;

&lt;h3&gt;
  
  
  Other articles that you might like...
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/redis-instalacion-y-configuracion" rel="noopener noreferrer"&gt;Redis - Instalación y Configuración&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/aws-s3-batch-operations" rel="noopener noreferrer"&gt;AWS S3 Batch Operations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/inventario-aws-s3" rel="noopener noreferrer"&gt;AWS S3 Inventory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/aws-elasticache" rel="noopener noreferrer"&gt;Qué ofrece y cómo se configura AWS Elasticache?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/aws-elasticache" rel="noopener noreferrer"&gt;Qué ofrece y cómo se configura Elasticache en AWS?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt; &lt;a href="https://juanc4milo.dev/redis-with-spring-in-java" rel="noopener noreferrer"&gt;How to use Redis with Spring in Java&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/send-email-with-aws-and-track-events" rel="noopener noreferrer"&gt;How to send an email with AWS SES and track events with Configuration Sets?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Do you like it?&lt;/strong&gt; You can &lt;a href="https://buymeacoffee.com/juanc4milo" rel="noopener noreferrer"&gt;buy me a beer&lt;/a&gt; if you want.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://juanc4milo.dev" rel="noopener noreferrer"&gt;juanc4milo.dev&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>aws</category>
      <category>ses</category>
      <category>cloud</category>
      <category>email</category>
    </item>
    <item>
      <title>How to send an email with AWS SES and track events with Configuration Sets?</title>
      <dc:creator>juanc4milo</dc:creator>
      <pubDate>Fri, 06 Nov 2020 15:21:50 +0000</pubDate>
      <link>https://dev.to/juanc4milo/how-to-send-an-email-with-aws-ses-and-track-events-with-configuration-sets-1f8b</link>
      <guid>https://dev.to/juanc4milo/how-to-send-an-email-with-aws-ses-and-track-events-with-configuration-sets-1f8b</guid>
      <description>&lt;p&gt;Amazon Simple Email Service is a flexible and scalable email service that allows you to send mail from within any application. &lt;/p&gt;

&lt;p&gt;Through this service, you can send emails and receive information on events that the recipient performs, such as mail delivered to the server, mail opening, or the recipient clicked on any link within the email.&lt;/p&gt;

&lt;p&gt;To achieve that, you need to do the following steps:&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify a Domain
&lt;/h2&gt;

&lt;p&gt;The first thing you need to do is enter the domain that the email account belongs to so that Amazon can verify that the domain is yours. To do this, enter the Domains section and enter the domain:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604518525966%2FcWSnzr7ww.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604518525966%2FcWSnzr7ww.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, on the DNS settings you own (Godaddy, Hostgator, route53, etc.), you must create and enter the verification record sets that Amazon delivers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604518890563%2FYBjGDDb0f.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604518890563%2FYBjGDDb0f.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604519317424%2F-8HYWbL8V.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604519317424%2F-8HYWbL8V.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Amazon must verify the domain, so you must enter this information in DNS settings.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;If you are using Cloudfare or any CDN, you must enter this settings too.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Just wait 5 minutes to propagate the changes around the DNSs...&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604519522061%2FZaBh-DAcX.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604519522061%2FZaBh-DAcX.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Verify Email address
&lt;/h2&gt;

&lt;p&gt;Additionally, Amazon must verify a valid and existing email account. To do this, you must enter Amazon SES to the Email Address section, enter the email account and then go to the inbox of the specified mailbox and click on the link that allows you to verify the account.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604523062213%2Fqb6nXBXPa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604523062213%2Fqb6nXBXPa.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Create a Configuration Set
&lt;/h2&gt;

&lt;p&gt;To create a set of configurations in Amazon SES, go to the Configuration Sets section and click on the Create Configuration Set button.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604524177211%2FXkYMuuv8M.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604524177211%2FXkYMuuv8M.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Assign a name to the Configuration Set:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604525686409%2FBKYaiXSiS.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604525686409%2FBKYaiXSiS.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After assigning the name, it appears with no destinations created:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604525730392%2F_Kubvcr-E.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604525730392%2F_Kubvcr-E.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Enter into the configuration set:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604525773310%2FrxQkHzDCa.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604525773310%2FrxQkHzDCa.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You select the way you want to report the events:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604525851154%2FY9X15SnQM.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604525851154%2FY9X15SnQM.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For this example, I enabled Amazon SNS:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604532895232%2F8j0uB_0M2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604532895232%2F8j0uB_0M2.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;AWS SES reported these types of events when they occur. Select the one that suits you best.:&lt;/p&gt;

&lt;p&gt;• &lt;strong&gt;Send:&lt;/strong&gt; A successful Amazon API call has been made to send mail and Amazon SES will attempt to deliver the mail.&lt;/p&gt;

&lt;p&gt;• &lt;strong&gt;Reject:&lt;/strong&gt; Amazon SES accepted the email but determined that it contained malware and rejected it, thus, the email will not be sent.&lt;/p&gt;

&lt;p&gt;• &lt;strong&gt;Delivery:&lt;/strong&gt; Amazon SES delivered the mail to the recipient's mail server.&lt;/p&gt;

&lt;p&gt;• &lt;strong&gt;Bounce:&lt;/strong&gt; The recipient's mail server has rejected the mail, due to many causes, such as the inbox is full or the recipient does not exist.&lt;/p&gt;

&lt;p&gt;• &lt;strong&gt;Complaint:&lt;/strong&gt; The email has been delivered to the recipient, but marks it as spam.&lt;/p&gt;

&lt;p&gt;• &lt;strong&gt;Click:&lt;/strong&gt; The recipient clicked on one or more links included in the email.&lt;/p&gt;

&lt;p&gt;• &lt;strong&gt;Open:&lt;/strong&gt; The recipient received the message and opened it in their email client.&lt;/p&gt;

&lt;p&gt;• &lt;strong&gt;Rendering Failure:&lt;/strong&gt; The mail has not been sent due to a problem with the reading of the designated template for the mail.&lt;/p&gt;

&lt;p&gt;• &lt;strong&gt;Rendering Success:&lt;/strong&gt; The email was sent using the templates configured in Amazon SES.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604533006339%2FFKmeniIeM.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604533006339%2FFKmeniIeM.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Select the SNS topic before configured to subscribe to notifications:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604532685895%2FXQTgMzlnA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604532685895%2FXQTgMzlnA.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Save the configuration and a box will display the information entered:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604533049434%2FjIvcQa_zN.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604533049434%2FjIvcQa_zN.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Test
&lt;/h2&gt;

&lt;p&gt;To send a test email, select the domain, and click on the Send a Test Email button:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604533108288%2FcTHIq2YSz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604533108288%2FcTHIq2YSz.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Then, enter the following fields, where the RAW field indicated the mail format:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604533548997%2FfOuCIarx2.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604533548997%2FfOuCIarx2.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Include the following text in the body of the message. This text includes a tag that indicates the  that AWS used to report the events:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

X-SES-CONFIGURATION-SET: myConfigSetsName
X-SES-MESSAGE-TAGS: DimensionName=DefaultValue
From: emailfrom@domainexample.com
To: emailto@domainexample.com
Subject: Test email
Content-Type: multipart/alternative;
    boundary="----=_boundary"

------=_boundary
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: 7bit

This is a test email with config sets.

&amp;lt;a href="https://aws.amazon.com/"&amp;gt;Amazon Web Services&amp;lt;/a&amp;gt;
------=_boundary


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Click on the send button and an email should reach the recipient's inbox:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604535729464%2FGQ5mtaQ4g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fcdn.hashnode.com%2Fres%2Fhashnode%2Fimage%2Fupload%2Fv1604535729464%2FGQ5mtaQ4g.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  One last thing...
&lt;/h2&gt;

&lt;p&gt;To report an open email, Amazon SES includes a blank image at the end of the email so that when the user opens the email, it triggers an event that AWS captured.&lt;/p&gt;

&lt;p&gt;For this reason, a restriction of the service is that the originating email account must be marked as a safe sender so when the recipient opens the email, it downloads all its content completely and could launch the event.&lt;/p&gt;

&lt;h3&gt;
  
  
  Other articles that you might like...
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/redis-instalacion-y-configuracion" rel="noopener noreferrer"&gt;Redis - Instalación y Configuración&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/aws-s3-batch-operations" rel="noopener noreferrer"&gt;AWS S3 Batch Operations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/inventario-aws-s3" rel="noopener noreferrer"&gt;AWS S3 Inventory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/aws-elasticache" rel="noopener noreferrer"&gt;Qué ofrece y cómo se configura AWS Elasticache?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/aws-elasticache" rel="noopener noreferrer"&gt;Qué ofrece y cómo se configura Elasticache en AWS?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt; &lt;a href="https://juanc4milo.dev/redis-with-spring-in-java" rel="noopener noreferrer"&gt;How to use Redis with Spring in Java&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Do you like it?&lt;/strong&gt; You can &lt;a href="https://buymeacoffee.com/juanc4milo" rel="noopener noreferrer"&gt;buy me a beer&lt;/a&gt; if you want.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://juanc4milo.dev" rel="noopener noreferrer"&gt;juanc4milo.dev&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>aws</category>
      <category>email</category>
      <category>ses</category>
      <category>cloud</category>
    </item>
    <item>
      <title>¿Qué ofrece y cómo se configura Elasticache en AWS?</title>
      <dc:creator>juanc4milo</dc:creator>
      <pubDate>Sat, 31 Oct 2020 16:10:41 +0000</pubDate>
      <link>https://dev.to/juanc4milo/que-ofrece-y-como-se-configura-elasticache-en-aws-5c7</link>
      <guid>https://dev.to/juanc4milo/que-ofrece-y-como-se-configura-elasticache-en-aws-5c7</guid>
      <description>&lt;h2&gt;
  
  
  ¿Qué ofrece Elasticache?
&lt;/h2&gt;

&lt;p&gt;Amazon ElastiCache ofrece como motor de base de datos de caché a Redis o Memcached de una forma completamente administrada.&lt;/p&gt;

&lt;p&gt;Principalmente, este servicio de AWS proporciona:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Soporte para dos motores: Memcached y Redis.&lt;/li&gt;
&lt;li&gt;Facilidad de administración a través de la consola de administración de AWS.&lt;/li&gt;
&lt;li&gt;Compatibilidad con el protocolo específico del motor. &lt;/li&gt;
&lt;li&gt;Estadísticas detalladas de monitoreo a través de Amazon CloudWatch.&lt;/li&gt;
&lt;li&gt;Pagar solo por los recursos que consume en función de las horas de nodo utilizadas.&lt;/li&gt;
&lt;li&gt;Está disponible en todas las regiones de AWS.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Configuración
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Preconfiguración: Grupo de Parámetros
&lt;/h3&gt;

&lt;p&gt;Antes de crear el servicio de ElastiCache en AWS, se recomienda pre-configurar el grupo de parámetros que va a tomar el servicio.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--CdBlObei--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603683959027/-Y8gvhrnz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--CdBlObei--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603683959027/-Y8gvhrnz.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Para crear un grupo de parámetros se da click en &lt;em&gt;Crear Grupo Parámetros&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--WnDsrIuj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603683987470/rA5rgLTA0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--WnDsrIuj--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603683987470/rA5rgLTA0.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Luego de crear el grupo, se Editan los parámetros según la necesidad (Los grupos de parámetros por «&lt;em&gt;defecto&lt;/em&gt;» no se pueden modificar):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Meb76MPB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603684162097/X9MG0ppwx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Meb76MPB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603684162097/X9MG0ppwx.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Al dar click en Editar parámetros se despliega una tabla donde se pueden modificar 48 parámetros de configuración de Redis:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--exHJkY_I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603684182085/O4-QdUFj5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--exHJkY_I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603684182085/O4-QdUFj5.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;El grupo de parámetros contiene 189 valores, de los cuales solo 48 son configurables por el usuario, el resto es administrado por AWS según el tipo de nodo que se escoge.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--l75PUXda--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603684205161/OcxlSA_Fk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--l75PUXda--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603684205161/OcxlSA_Fk.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Parámetros de configuración
&lt;/h3&gt;

&lt;p&gt;Para crear un clúster de Amazon ElastiCache, Amazon solicita:&lt;/p&gt;

&lt;h4&gt;
  
  
  1. Seleccionar motor de clúster:
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oY-fe0mo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603684286660/M1c12G85j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oY-fe0mo--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603684286660/M1c12G85j.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h4&gt;
  
  
  2. Parámetros básicos
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--L9JACxf4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603684350731/lDHPYpxDN.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--L9JACxf4--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603684350731/lDHPYpxDN.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Nota&lt;/em&gt;: Los &lt;em&gt;grupos de parámetros&lt;/em&gt; son un conjunto de valores que se pueden aplicar a uno o varios contenedores, y contiene los valores personalizado que se definieron en el primer paso de &lt;em&gt;preconfiguración&lt;/em&gt;. Se pueden crear varios grupos de parámetros y aquí permite seleccionar el grupo que se haya creado previamente. Este grupo de parámetros son los valores que va a tomar como configuración el motor &lt;a href="https://juanc4milo.dev/redis-instalacion-y-configuracion"&gt;Redis&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  3. Parámetros avanzados
&lt;/h4&gt;

&lt;p&gt;Permite seleccionar el grupo de subredes a la que va a pertenecer el clúster de AWS ElastiCache. Permite seleccionar zonas de disponibilidad preferidas.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qyznCJt6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603684505545/qx5KOQdwy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qyznCJt6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603684505545/qx5KOQdwy.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Nota&lt;/em&gt;: El parámetro «&lt;em&gt;Multi-AZ con conmutación por error automática&lt;/em&gt;» permite indicar que el servicio tenga disponibilidad mejorada a través de la conmutación por errores automática, lo que hace que cambie a una réplica de solo lectura en caso que exista falla en el nodo principal.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h4&gt;
  
  
  4. Parámetros de seguridad
&lt;/h4&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YIizWKZN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603684675589/zrZOE6qU6.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YIizWKZN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603684675589/zrZOE6qU6.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;ul&gt;
&lt;li&gt;El parámetro «&lt;em&gt;Cifrado en reposo&lt;/em&gt;» habilita el cifrado de los datos almacenados en el disco. Actualmente, solo se puede habilitar el cifrado en reposo cuando se crea un clúster de Redis en la versión 3.2.6.&lt;/li&gt;
&lt;li&gt;El parámetro «&lt;em&gt;Cifrado en tránsito&lt;/em&gt;» habilita el cifrado de los datos durante su transmisión. Actualmente, solo se puede habilitar el cifrado en tránsito cuando se crea un clúster de Redis en la versión 3.2.6.&lt;/li&gt;
&lt;li&gt;El parámetro «&lt;em&gt;Ubicación en S3 del archivo RDB&lt;/em&gt;» es una ruta de un bucket S3 que contiene una copia de seguridad de un archivo tipo RDB de Redis que tengamos externo para propagar datos en la nueva base de datos que se va a crear.&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Luego de configurar, ¿Qué acciones puedo hacer con el servicio?
&lt;/h3&gt;

&lt;p&gt;Las acciones permitidas sobre el servicio ElastiCache tipo Redis en AWS son:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Crear.&lt;/li&gt;
&lt;li&gt;Copia Seguridad.&lt;/li&gt;
&lt;li&gt;Reiniciar.&lt;/li&gt;
&lt;li&gt;Eliminar.&lt;/li&gt;
&lt;li&gt;Modificar.&lt;/li&gt;
&lt;li&gt;Aplicar actualización servicio.&lt;/li&gt;
&lt;li&gt;Ver/Detener actualización.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Costos
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Tipos de nodos
&lt;/h3&gt;

&lt;p&gt;Los principales tipos de nodos para crear nuestra base de datos de Elasticache son:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xC_P47QZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603684989945/u0agaN_Oj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xC_P47QZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603684989945/u0agaN_Oj.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6MI804g3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603685028175/1cxMeBh1O.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6MI804g3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603685028175/1cxMeBh1O.png" alt="image.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En un modelo de nodos por demanda, dependiendo del tipo de nodo que se seleccione y la región de AWS, los precios fluctúan entre $0,017 USD y $7,00 USD por hora.&lt;/p&gt;

&lt;p&gt;Bajo un modelo de nodos reservados, ya sea entre 1 y 3 años, los precios varían entre $0,009 USD y $6,604 USD por hora.&lt;/p&gt;

&lt;p&gt;Ver &lt;a href="https://aws.amazon.com/es/elasticache/pricing/?nc=sn&amp;amp;loc=5"&gt;tabla de precios&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Almacenamiento backup
&lt;/h3&gt;

&lt;p&gt;El almacenamiento adicional de copias de seguridad tiene un valor de $0,085 USD/GB al mes y es el mismo valor para todas las regiones.&lt;/p&gt;

&lt;h3&gt;
  
  
  Transferencia de datos
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;No cobran por transferencia de datos entre una instancia de Amazon EC2 y el nodo de Elasticache si se encuentran dentro de la misma zona de disponibilidad.&lt;/li&gt;
&lt;li&gt;Se cobra $0,01 USD por cada GB de entrada/salida entre una instancia de Amazon EC2 y el nodo de Elasticache si se encuentra entre una zona de disponibilidad diferente o en regiones diferentes.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Otros artículos que te podrían interesar...
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/redis-instalacion-y-configuracion"&gt;Redis - Instalación y Configuración&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/aws-s3-batch-operations"&gt;AWS S3 Batch Operations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/inventario-aws-s3"&gt;AWS S3 Inventory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/aws-elasticache"&gt;Qué ofrece y cómo se configura AWS Elasticache?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt; &lt;a href="https://juanc4milo.dev/redis-with-spring-in-java"&gt;How to use Redis with Spring in Java&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Do you like it?&lt;/strong&gt; &lt;a href="https://buymeacoffee.com/juanc4milo"&gt;Buy me a beer&lt;/a&gt; if you want.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://juanc4milo.dev"&gt;juanc4milo.dev&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>database</category>
      <category>redis</category>
      <category>aws</category>
      <category>elasticache</category>
    </item>
    <item>
      <title>How to use Redis with Spring in Java</title>
      <dc:creator>juanc4milo</dc:creator>
      <pubDate>Fri, 30 Oct 2020 15:25:16 +0000</pubDate>
      <link>https://dev.to/juanc4milo/how-to-use-redis-with-spring-in-java-930</link>
      <guid>https://dev.to/juanc4milo/how-to-use-redis-with-spring-in-java-930</guid>
      <description>&lt;p&gt;In a Java Project, you must include the following dependencies to use Redis database:&lt;/p&gt;

&lt;h5&gt;
  
  
  1.Use the Spring Data redis
&lt;/h5&gt;

&lt;p&gt;&lt;em&gt;with Maven:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;org.springframework.data&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;spring-data-redis&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;2.3.4.RELEASE&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;with Gradle:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;compile group: 'org.springframework.data', name: 'spring-data-redis', version: '2.3.4.RELEASE'

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h5&gt;
  
  
  2.Use Jedis as client connector
&lt;/h5&gt;

&lt;p&gt;&lt;em&gt;with Maven:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;dependency&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;groupId&amp;gt;&lt;/span&gt;redis.clients&lt;span class="nt"&gt;&amp;lt;/groupId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;artifactId&amp;gt;&lt;/span&gt;jedis&lt;span class="nt"&gt;&amp;lt;/artifactId&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;version&amp;gt;&lt;/span&gt;3.3.0&lt;span class="nt"&gt;&amp;lt;/version&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/dependency&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;with Gradle:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;compile group: 'redis.clients', name: 'jedis', version: '3.3.0'
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, in your project create a Redis Context File to declare objects which define the connections settings to Redis server:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" encoding="UTF-8"?&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;beans&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://www.springframework.org/schema/beans"&lt;/span&gt;
       &lt;span class="na"&gt;xmlns:context=&lt;/span&gt;&lt;span class="s"&gt;"http://www.springframework.org/schema/context"&lt;/span&gt;  
       &lt;span class="na"&gt;xmlns:xsi=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2001/XMLSchema-instance"&lt;/span&gt;
       &lt;span class="na"&gt;xmlns:p=&lt;/span&gt;&lt;span class="s"&gt;"http://www.springframework.org/schema/p"&lt;/span&gt;
       &lt;span class="na"&gt;xsi:schemaLocation=&lt;/span&gt;&lt;span class="s"&gt;"http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/context 
    http://www.springframework.org/schema/context/spring-context.xsd"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;bean&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"jedisPoolConfig"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"redis.clients.jedis.JedisPoolConfig"&lt;/span&gt;
          &lt;span class="na"&gt;p:max-total=&lt;/span&gt;&lt;span class="s"&gt;"${redis.config.pool.maxTotal}"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;bean&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"jedisConnectionFactory"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"org.springframework.data.redis.connection.jedis.JedisConnectionFactory"&lt;/span&gt;
          &lt;span class="na"&gt;p:host-name=&lt;/span&gt;&lt;span class="s"&gt;"${redis.config.hostname}"&lt;/span&gt; 
          &lt;span class="na"&gt;p:port=&lt;/span&gt;&lt;span class="s"&gt;"${redis.config.port}"&lt;/span&gt; 
          &lt;span class="na"&gt;p:use-pool=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;constructor-arg&lt;/span&gt; &lt;span class="na"&gt;ref=&lt;/span&gt;&lt;span class="s"&gt;"jedisPoolConfig"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/bean&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;bean&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"redisTemplate"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"org.springframework.data.redis.core.RedisTemplate"&lt;/span&gt; 
          &lt;span class="na"&gt;p:connection-factory-ref=&lt;/span&gt;&lt;span class="s"&gt;"jedisConnectionFactory"&lt;/span&gt; 
          &lt;span class="na"&gt;p:enable-transaction-support=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;bean&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"stringRedisTemplate"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"org.springframework.data.redis.core.StringRedisTemplate"&lt;/span&gt; 
          &lt;span class="na"&gt;p:connection-factory-ref=&lt;/span&gt;&lt;span class="s"&gt;"jedisConnectionFactory"&lt;/span&gt; 
          &lt;span class="na"&gt;p:enable-transaction-support=&lt;/span&gt;&lt;span class="s"&gt;"true"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;  
&lt;span class="nt"&gt;&amp;lt;/beans&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Include some properties defined in the bean objects to the application.properties file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#Redis Config
redis.config.hostname=127.0.0.1
redis.config.port=6379
redis.config.pool.maxTotal=5
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In your persistence context or main spring-context, inject the RedisTemplate bean into the DAO bean object that you want to use Redis cache, for example in a TransactionDao object:&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Context:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;bean&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"transactionDao"&lt;/span&gt; &lt;span class="na"&gt;class=&lt;/span&gt;&lt;span class="s"&gt;"com.juanc4milo.persistence.dao.TransactionDao"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;property&lt;/span&gt; &lt;span class="na"&gt;name=&lt;/span&gt;&lt;span class="s"&gt;"redisTemplate"&lt;/span&gt; &lt;span class="na"&gt;ref=&lt;/span&gt;&lt;span class="s"&gt;"redisTemplate"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/bean&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;TransactionDao class:&lt;/em&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nd"&gt;@Autowired&lt;/span&gt;
&lt;span class="kd"&gt;private&lt;/span&gt; &lt;span class="nc"&gt;RedisTemplate&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Transaction&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;redisTemplate&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then create an instance of the ValueOperations class to operate with the Redis database.&lt;/p&gt;

&lt;p&gt;To set a value in database use the method &lt;em&gt;SET&lt;/em&gt; from ValueOperations class, like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;valueOperation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;,&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The transaction ID will be the key in Redis database, and the entire object Transaction will be the value. After that, you could set the expiration time in seconds, minutes, hours, etc.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;ValueOperations&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Transaction&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;valueOperation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;redisTemplate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;opsForValue&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;valueOperation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;set&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;redisTemplate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;expire&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transaction&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;getId&lt;/span&gt;&lt;span class="o"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;3600&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;TimeUnit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;SECONDS&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Redis allows cache of different types of values, such as:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Values&lt;/li&gt;
&lt;li&gt;Sets&lt;/li&gt;
&lt;li&gt;Sorted sets&lt;/li&gt;
&lt;li&gt;Hashes&lt;/li&gt;
&lt;li&gt;Lists&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To get the data from Redis database, use the method &lt;em&gt;GET&lt;/em&gt; from ValueOperations class, like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;valueOperation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&amp;lt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;key&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&amp;gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="nc"&gt;ValueOperations&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nc"&gt;String&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;Transaction&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;valueOperation&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;redisTemplate&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;opsForValue&lt;/span&gt;&lt;span class="o"&gt;();&lt;/span&gt;
&lt;span class="nc"&gt;Transaction&lt;/span&gt; &lt;span class="n"&gt;tx&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;valueOperation&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;get&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;transactionId&lt;/span&gt;&lt;span class="o"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Other articles of mine that you might like...
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/redis-instalacion-y-configuracion"&gt;Redis - Instalación y Configuración&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/aws-s3-batch-operations"&gt;AWS S3 Batch Operations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/inventario-aws-s3"&gt;AWS S3 Inventory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/aws-elasticache"&gt;Qué ofrece y cómo se configura AWS Elasticache?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/aws-elasticache"&gt;Qué ofrece y cómo se configura Elasticache en AWS?&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Do you like it?&lt;/strong&gt; You can &lt;a href="https://buymeacoffee.com/juanc4milo"&gt;buy me a beer&lt;/a&gt; if you want.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://juanc4milo.dev"&gt;juanc4milo.dev&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>redis</category>
      <category>java</category>
      <category>spring</category>
      <category>cache</category>
    </item>
    <item>
      <title>Redis - Instalación y Configuración</title>
      <dc:creator>juanc4milo</dc:creator>
      <pubDate>Mon, 26 Oct 2020 02:22:44 +0000</pubDate>
      <link>https://dev.to/juanc4milo/redis-instalacion-y-configuracion-213j</link>
      <guid>https://dev.to/juanc4milo/redis-instalacion-y-configuracion-213j</guid>
      <description>&lt;h2 id="redis-que-es"&gt;¿Qué es?&lt;/h2&gt;

&lt;p&gt;Redis es un almacén de estructura de datos en memoria y es de código abierto (licencia BSD), que se utiliza como agente de base de datos, caché o bróker de mensajería. Admite estructuras de datos como cadenas, hashes, listas, conjuntos o conjuntos ordenados.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iIHO9p0_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603519527691/A0Vr68m6G.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iIHO9p0_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603519527691/A0Vr68m6G.png" alt="redis318x260_1.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id="redis-vs-memcached"&gt;Redis vs Memcached&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://redis.io"&gt;Redis&lt;/a&gt; y &lt;a href="https://memcached.org"&gt;Memcached&lt;/a&gt; son sistemas de almacenamiento de datos en memoria.&lt;/p&gt;

&lt;p&gt;Tanto Memcached como Redis sirven como almacén de datos clave-valor en memoria, aunque Redis se describe con mayor precisión como un almacén de estructura de datos.&lt;/p&gt;

&lt;p&gt;Tanto Memcached como Redis pertenecen a la familia de soluciones de gestión de datos NoSQL, y ambas se basan en un modelo de datos clave-valor. Ambos mantienen todos los datos en la RAM, lo que, por supuesto, los hace sumamente útiles como capa de almacenamiento en caché.&lt;/p&gt;

&lt;p&gt;Las principales características de Redis frente a Memcached son:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Redis admite operaciones de datos más completas que Memcached. Posee más estructura de datos (sorted set, hash, list, etc).&lt;/li&gt;
&lt;li&gt;Eficiencia de uso de memoria. Memcached tiene una tasa de utilización de memoria más alta para un simple almacenamiento de clave-valor. Redis utiliza un modo de compresión de data en memoria.&lt;/li&gt;
&lt;li&gt;Redis solo usa núcleos individuales, mientras que Memcached utiliza múltiples núcleos. Entonces, en promedio, Redis cuenta con un rendimiento más alto que Memcached en el almacenamiento de datos pequeños cuando se mide en términos de núcleos.&lt;/li&gt;
&lt;li&gt;Memcached solo usa una política de vaciado de cache, con el algoritmo LRU (menos recientemente usado). Redis soporta 6 diferentes tipos de política (con algoritmo LRU y LFU).&lt;/li&gt;
&lt;li&gt;Redis &lt;a rel="noreferrer noopener" href="https://docs.oracle.com/cd/E17952_01/mysql-5.6-en/ha-memcached-faq.html#faq-memcached-max-object-size"&gt;soporta valores de hasta 512 MB&lt;/a&gt; de tamaño. Memcached limitada a 1 MB por clave-valor.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="instalacion-redis-server"&gt;Instalación de Redis Server&lt;/h2&gt;

&lt;h3 id="redis-server-windows"&gt;Redis Server en Windows&lt;/h3&gt;

&lt;p&gt;Para Windows existe una versión no oficial de la aplicación donde un usuario ha tomado los compilados y los ha puesto a disposición para trabajar en el sistema operativo Windows.&lt;/p&gt;

&lt;p&gt;El instalador se obtiene del siguiente enlace según recomendaciones del sitio RedisLab:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/dmajkic/redis/downloads" rel="noreferrer noopener"&gt;https://github.com/dmajkic/redis/downloads&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Luego de descargar el archivo, descomprimir el zip que contiene todos los binarios de la aplicación.&lt;/p&gt;

&lt;p&gt;Abrir consola de Windows, y ubicarse en la carpeta donde se encuentran los archivos de Redis. Para iniciar el servidor Redis se ejecuta el comando:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&lt;em&gt;redis-server.exe&lt;/em&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jJ6IMkdB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603519614470/4RpHu3nwX.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jJ6IMkdB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603519614470/4RpHu3nwX.png" alt="image-33.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Para verificar que está corriendo correctamente el servidor Redis, en otra consola de comandos, nos ubicamos nuevamente en la carpeta donde se encuentran los archivos de Redis y se ejecuta el cliente:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;&lt;em&gt;redis-cli.exe&lt;/em&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6Yi_L4XI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603519629499/n4Ug4iP5j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6Yi_L4XI--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603519629499/n4Ug4iP5j.png" alt="image-34.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Una vez se ingresa en la consola cliente, se puede usar el comando PING y el servidor nos debe contestar con PONG.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--77HbkBKr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603519643140/stR4DOzYG.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--77HbkBKr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603519643140/stR4DOzYG.png" alt="image-35.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id="redis-server-linux"&gt;Redis Server en Linux&lt;/h3&gt;

&lt;h4 id="redis-server-linux-binaries"&gt;Por medio de binarios&lt;/h4&gt;

&lt;p&gt;Descargar la versión de Redis para Linux del siguiente enlace:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://redis.io/download" rel="noreferrer noopener"&gt;https://redis.io/download&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;o con el comando:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ &lt;em&gt;wget https://download.redis.io/releases/redis-6.0.8.tar.gz&lt;/em&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Luego, descomprimir el tar.gz que contiene todos los binarios de la aplicación.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ &lt;em&gt;tar xzf redis-6.0.8.tar.gz&lt;/em&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Ingresar a la carpeta, y compilar los binarios:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ &lt;em&gt;cd redis-6.0.8&lt;/em&gt;&lt;br&gt;$ &lt;em&gt;make&lt;/em&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Una vez compilada la solución se usa el siguiente comando para ejecutar Redis server:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ &lt;em&gt;src/redis-server&lt;/em&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Una vez verificado que corre, se puede seguir con la creación del archivo &lt;em&gt;.service&lt;/em&gt; para dejar la aplicación como servicio.&lt;/p&gt;

&lt;h4 id="redis-server-linux-repository"&gt;Por medio del repositorio&lt;/h4&gt;

&lt;p&gt;Descargar el rpm del siguiente enlace:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ &lt;em&gt;wget http://rpms.remirepo.net/enterprise/7/remi/x86_64/redis-devel-6.0.8-1.el7.remi.x86_64.rpm&lt;/em&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Instalar el rpm con el siguiente comando:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ &lt;em&gt;sudo yum install redis-6.0.8-1.el7.remi.x86_64.rpm&lt;/em&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Para iniciar el servicio:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ &lt;em&gt;sudo systemctl start redis.service&lt;/em&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;h2 id="redis-conf"&gt;Configuración&lt;/h2&gt;

&lt;p&gt;La configuración de Redis se realiza por medio del archivo &lt;em&gt;&lt;strong&gt;/etc/redis.conf&lt;/strong&gt;&lt;/em&gt; y está dividido en diferentes secciones. Los parámetros de configuración más más importantes corresponden a los siguientes:&lt;/p&gt;

&lt;h3 id="redis-conf-includes"&gt;INCLUDES&lt;/h3&gt;

&lt;p&gt;Permite incluir uno o más archivos adicionales de configuración. Ejemplo:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# include /path/to/local.conf&lt;br&gt;# include /path/to/other.conf&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="redis-conf-modules"&gt;MODULES&lt;/h3&gt;

&lt;p&gt;Permite cargar modulos al inicio de la aplicación. Ejemplo:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# loadmodule /path/to/my_module.so&lt;br&gt;# loadmodule /path/to/other_module.so&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="redis-conf-network"&gt;NETWORK&lt;/h3&gt;

&lt;p&gt;Permite configurar las directivas de red de la aplicación, tales como interfaces por las que debe escuchar conexiones. Si no se especifica ningún enlace, la aplicación escucha por todas las interfaces de red disponibles en el servidor. Por defecto el modo protección se encuentra habilitado, escuchando solo por la interfaz de red local 127.0.0.1. Para permitir conexiones desde otros servidores se deben especificar en esta sección. El puerto por defecto de la aplicación es 6379. El tiempo timeout por defecto es 0, quiere decir que esta deshabilitado. Para mantener viva a conexión TCP por defecto está en 300 segundos donde la aplicación envía ACKs para saber si los clientes están con conexión activa. Ejemplo:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# bind 192.168.1.100 10.0.0.1&lt;br&gt;# bind 127.0.0.1 ::1&lt;br&gt;# protected-mode yes&lt;br&gt;# port 6379&lt;br&gt;# timeout 0&lt;br&gt;# tcp-keepalive 300&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="redis-conf-general"&gt;GENERAL&lt;/h3&gt;

&lt;p&gt;Por defecto, Redis no corre como un deamon&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# daemonize no&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Por defecto, Redis corre sin modo de supervisado, de modo que si el servicio se detiene, no se informa al sistema del estado del servicio. Se puede especificar: &lt;em&gt;upstart&lt;/em&gt;, &lt;em&gt;systemd&lt;/em&gt; o &lt;em&gt;auto&lt;/em&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# supervised no&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Se puede especificar el archivo donde va a estar registrado el id del proceso de la máquina.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# pidfile /var/run/redis_6379.pid&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Se puede especificar el nivel de logger que tendrá la aplicación. Maneja los niveles: &lt;em&gt;debug&lt;/em&gt;, &lt;em&gt;verbose&lt;/em&gt;, &lt;em&gt;notice&lt;/em&gt; y &lt;em&gt;warning&lt;/em&gt;. Por defecto está en &lt;em&gt;notice&lt;/em&gt;, que es moderado y especializado para ambientes productivos.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# loglevel notice&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Se puede especificar el nombre del archivo log del servicio.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# logfile /var/log/redis/redis.log&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Se puede especificar logging en el logger del sistema.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# syslog-enabled no&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Se puede especificar la cantidad de base de datos que el servicio va a emplear.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# databases 16&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="redis-conf-snapshotting"&gt;SNAPSHOTTING&lt;/h3&gt;

&lt;p&gt;Permite guardar cambios en la base de datos después del tiempo especificado. Ejemplo:&lt;/p&gt;

&lt;p&gt;Guarda si:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Después de 900 segundos si al menos hay un cambio&lt;/li&gt;
&lt;li&gt;Después de 300 segundos si al menos hay 10 cambios&lt;/li&gt;
&lt;li&gt;Después de 60 segundos si al menos hay 10000 cambios.&lt;/li&gt;
&lt;/ul&gt;

&lt;pre&gt;&lt;code&gt;# save &amp;lt;seconds&amp;gt; &amp;lt;changes&amp;gt;&lt;br&gt;save 900 1&lt;br&gt;save 300 10&lt;br&gt;save 60 10000&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Se puede especificar el nombre de archivo de la base de datos y el sitio donde estará ubicado.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# dbfilename dump.rdb&lt;br&gt;# dir /var/lib/redis&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="redis-conf-replication"&gt;REPLICATION&lt;/h3&gt;

&lt;p&gt;Permite configurar replicación de la información entre un servidor maestro y un esclavo. La replicación en redis es asíncrona. La réplica de redis tiene la capacidad de resincronizar parcialmente con la master si se llega a perder una pequeña cantidad de tiempo en el enlace de conexión. La replicación es automática y no requiere de intervención del usuario. Para indicar la máquina donde se va a realizar la réplica se debe habilitar lo siguiente:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# replicaof &amp;lt;masterip&amp;gt; &amp;lt;masterport&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Si la máquina master está protegida por contraseña se puede indicar en esta sección:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# masterauth &amp;lt;master-password&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Si la réplica pierde conexión con la master, por defecto, redis puede seguir contestando a las peticiones pero tal vez con data obsoleta o vacía. Se puede habilitar por configuración que redis trabaje siempre sincronizado con la master ajustando el parámetro de data obsoleta en no.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# replica-serve-stale-data yes&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Redis permite configurar para que la réplica sea de solo lectura:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# replica-read-only yes&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Redis permite configurar que las réplicas se realizan mediante un proceso de full sincronización donde se transmite toda la información a copiar creando un proceso dedicado en la maquina a escribir un archivo en el disco para pasar toda la información. Si se requiere que no se use el disco para evitar latencia de escritura de disco, se puede habilitar otra opción para que la sincronización sea por medio de sockets. Si la sincronización por sockets está habilitada se puede indicar el tiempo de espera en segundos entre transferencia de datos.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# repl-diskless-sync no&lt;br&gt;# repl-diskless-sync-delay 5&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Las réplicas envían un comando PING hacia master cada cierto tiempo para validar conexión. Este valor por defecto está en 10 segundos.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# repl-ping-replica-period 10&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Redis permite configurar un tiempo de &lt;em&gt;timeout&lt;/em&gt; en segundos, entre la réplica y la master.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# repl-timeout 60&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Redis permite configurar latencia de trafico TCP, por defecto esta deshabilitado, lo que indica que los paquetes TCP van a viajar con toda la información y ocupando todo el ancho de banda disponible. Si esta opción se habilita, se usan paquetes TCP más pequeños de información, usando menos ancho de banda, pero añadiendo una latencia en la transferencia de información.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# repl-disable-tcp-nodelay no&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Redis permite configurar prioridad entre las réplicas, indicando un valor entre 0 y 100. Entre mayor sea el número, más prioridad tiene sobre esa replica. Si tiene un valor de cero, nunca va a ser tenido en cuenta para realizar replica. Por defecto el valor está en 100.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# replica-priority 100&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Redis permite configurar la cantidad mínima de réplicas que se requiera para escribir data, y el tiempo máximo de latencia entre las réplicas. Si no se cumple con alguno de los escenarios, la master detiene las escrituras. Por defecto la cantidad mínima de réplicas esta deshabilitada y el tiempo de latencia está en 10 segundos.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# min-replicas-to-write 3&lt;br&gt;# min-replicas-max-lag 10&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="redis-conf-security"&gt;SECURITY&lt;/h3&gt;

&lt;p&gt;Redis permite configurar un password de autenticación para la conexión de los clientes al servidor redis.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# requirepass foobared&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Redis permite configurar renombramiento de los comandos, en especial de los más vulnerables como el comando CONFIG. Con esto se podría renombrar a algo que sea difícil de adivinar.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# rename-command CONFIG b840fc02d524045429941cc15&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="redis-conf-clients"&gt;CLIENTS&lt;/h3&gt;

&lt;p&gt;Redis permite configurar el máximo número de clientes conectados al mismo tiempo. Por defecto, el número máximo es 10.000 clientes. Cuando se sobrepasa la cantidad, redis cierra todas las nuevas conexiones y envía un mensaje de error indicando que el número máximo de clientes ha sido alcanzado.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# maxclients 10000&lt;/code&gt;&lt;/pre&gt;

&lt;h3 id="redis-conf-memory-management"&gt;MEMORY MANAGEMENT&lt;/h3&gt;

&lt;p&gt;Redis permite configurar el límite de cantidad de memoria disponible en bytes. Cuando se alcanza el límite, redis va a intentar remover llaves de acuerdo a la política de expulsión de data seleccionada.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# maxmemory &amp;lt;bytes&amp;gt;&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Las políticas disponibles para indicar el comportamiento que debe tener redis cuando se alcanza el límite máximo de memoria son las siguientes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;volatile-lru&lt;/em&gt;: Expulsa usando la cantidad de llaves LRU entre un conjunto de llaves a expirar.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;allkeys-lru&lt;/em&gt;: Expulsa cualquier llave entre LRU.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;volatile-lfu&lt;/em&gt;: Expulsa usando la cantidad de llaves LFU entre un conjunto de llaves a expirar.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;allkeys-lfu&lt;/em&gt;: Expulsa cualquier llave entre LFU.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;volatile-random&lt;/em&gt;: Remueve llaves aleatoriamente entre un conjunto que tengan definido expiración.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;allkeys-random&lt;/em&gt;: Remueve aleatoriamente cualquier tipo de llave.&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;volatile-ttl&lt;/em&gt;: Remueve llaves con el tiempo más cercano de expiracion. (menor TTL)&lt;/li&gt;
&lt;li&gt;
&lt;em&gt;noeviction&lt;/em&gt;: No expulsa nada. Retorna un error para las operaciones de escritura.&lt;ul&gt;&lt;li&gt;LRU significa Least Recently Used – Menos usado reciemente.&lt;/li&gt;&lt;/ul&gt;
&lt;ul&gt;&lt;li&gt;LFU significa Least Frequently Used – Menos usado frecuentemente.&lt;/li&gt;&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Por defecto, redis está configurado con la política &lt;em&gt;noeviction&lt;/em&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# maxmemory-policy noeviction&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Redis toma muestras de la data para calcular los LRU y LFU. Redis permite configurar la cantidad de muestras a tomar. Por defecto está en 5 para dar buenos resultados. Un valor de 10 mejora notablemente la estadística pero consume mucha CPU, un valor de 3 hace que sea mucho más rápido pero la estadística no sea tan acertada.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;maxmemory-samples 5&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;
  
  
  Otros artículos que te podrían interesar...
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/aws-s3-batch-operations"&gt;AWS S3 Batch Operations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/inventario-aws-s3"&gt;AWS S3 Inventory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/aws-elasticache"&gt;Qué ofrece y cómo se configura AWS Elasticache?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/aws-elasticache"&gt;Qué ofrece y cómo se configura Elasticache en AWS?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt; &lt;a href="https://juanc4milo.dev/redis-with-spring-in-java"&gt;How to use Redis with Spring in Java&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Do you like it?&lt;/strong&gt; You can &lt;a href="https://buymeacoffee.com/juanc4milo"&gt;buy me a beer&lt;/a&gt; if you want.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://juanc4milo.dev"&gt;juanc4milo.dev&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>redis</category>
      <category>database</category>
      <category>cache</category>
      <category>caching</category>
    </item>
    <item>
      <title>AWS S3 Batch Operations</title>
      <dc:creator>juanc4milo</dc:creator>
      <pubDate>Mon, 26 Oct 2020 01:49:29 +0000</pubDate>
      <link>https://dev.to/juanc4milo/aws-s3-batch-operations-53eh</link>
      <guid>https://dev.to/juanc4milo/aws-s3-batch-operations-53eh</guid>
      <description>&lt;h2 id="batch-ops-what-is"&gt;¿Qué es?&lt;/h2&gt;

&lt;p&gt;Batch operations o en español, operaciones por lotes de S3, es una funcionalidad de AWS para realizar acciones por lotes a gran escala en objetos de Amazon S3. Se utiliza para copiar objetos, establecer etiquetas de objetos o listas de control de acceso (ACL), iniciar restauraciones de objetos desde Amazon S3 Glacier o invocar una función de AWS Lambda para realizar acciones personalizadas con los objetos.&lt;/p&gt;

&lt;h2 id="batch-ops-prerequisites"&gt;Prerequisitos&lt;/h2&gt;

&lt;p&gt;Como prerequisito para el uso de esta funcionalidad, es necesario tener lo siguiente:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Listado de los objetos en un archivo CSV o archivo manifiesto JSON generado por la funcionalidad &lt;a href="https://juanc4milo.dev/inventario-aws-s3/"&gt;Inventario de AWS S3&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Política de permisos en IAM.&lt;/li&gt;
&lt;li&gt;Rol en IAM.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3 id="batch-ops-prerequisites-list-objects"&gt;Listado de los objetos&lt;/h3&gt;

&lt;p&gt;Para realizar un trabajo por lotes con objetos de AWS S3, es necesario tener un archivo con el listado de todos los objetos que se requiere realizar alguna acción por lotes. Este listado se puede generar manualmente en formato CSV con la estructura: &lt;code&gt;NombreBucket, LlaveObjeto&lt;/code&gt;. Sin embargo, esta tarea puede ser algo compleja, para ello Amazon dispone de una funcionalidad llamada Inventory (Inventario) que permite generar este archivo, el cual para su configuración y uso se puede revisar en la entrada: &lt;a href="https://juanc4milo.dev/inventario-aws-s3/"&gt;Inventario AWS S3&lt;/a&gt;&lt;/p&gt;

&lt;h3 id="batch-ops-prerequisites-policy"&gt;Política de permisos en IAM&lt;/h3&gt;

&lt;p&gt;Para la correcta ejecución de S3 Batch Operation, se debe de contar con una política de permisos que permite al servicio S3 ejecutar las acciones sobre los recursos de la cuenta. Para ello se debe crear una política que luego será asociada a un Rol de IAM.&lt;/p&gt;

&lt;p&gt;Para ello se ingresa en IAM y se crea una política:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--v9-wqGD3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/wcbgbsppcgh3to9ph975.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--v9-wqGD3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/wcbgbsppcgh3to9ph975.png" alt="create-policy"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;El JSON de la política debe describir los permisos sobre:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Lectura de objetos que servirán de insumo para realizar las acciones por lote (bucket 1)&lt;/li&gt;
&lt;li&gt;Escritura de objetos hacia donde se va dirigida la acción por lote (bucket 2)&lt;/li&gt;
&lt;li&gt;Escritura de objetos donde será ubicado el reporte de generación de resultado de la tarea por lote.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Ejemplo:&lt;/p&gt;

&lt;pre&gt;{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Action": [
                "s3:PutObject",
                "s3:PutObjectAcl",
                "s3:PutObjectTagging"
            ],
            "Effect": "Allow",
            "Resource": "arn:aws:s3:::bucket-2/*"
        },
        {
            "Action": [
                "s3:GetObject",
                "s3:GetObjectAcl",
                "s3:GetObjectTagging"
            ],
            "Effect": "Allow",
            "Resource": "arn:aws:s3:::bucket-1/*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:GetObject",
                "s3:GetObjectVersion",
                "s3:GetBucketLocation"
            ],
            "Resource": [
                "arn:aws:s3:::bucket-1/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetBucketLocation"
            ],
            "Resource": [
                "arn:aws:s3:::bucket-1/*"
            ]
        }
    ]
}
&lt;/pre&gt;

&lt;p&gt;Luego se revisa que la política este bien creada, se le asigna un nombre y una descripción:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ApX-lRlf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/jf3uzblwb9hfmk9i67rf.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ApX-lRlf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/jf3uzblwb9hfmk9i67rf.png" alt="policy-name-description"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Una vez creada la política de permisos se debe ver en el listado de políticas de la cuenta:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--K-5tD7AY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/lmt38itj2cumt6yzp5vq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--K-5tD7AY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://dev-to-uploads.s3.amazonaws.com/i/lmt38itj2cumt6yzp5vq.png" alt="policies-list"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3 id="batch-ops-prerequisites-role"&gt;Configuración Rol en IAM&lt;/h3&gt;

&lt;p&gt;Para la correcta ejecución de S3 Batch Operation, se debe de contar con un rol que permite al servicio S3 ejecutar las acciones sobre los recursos de la cuenta según las políticas que tenga asociado el rol.&lt;/p&gt;

&lt;p&gt;Para ello se ingresa en IAM y se crea un rol:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GilHd28P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513400985/BLrkd_ZFu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GilHd28P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513400985/BLrkd_ZFu.png" alt="image-5.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Se selecciona que el rol será creado para que &lt;strong&gt;S3 Batch Operation&lt;/strong&gt; pueda ejecutar acciones sobre la cuenta:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YU56gDie--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513417345/w2DvHDA_q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YU56gDie--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513417345/w2DvHDA_q.png" alt="image-6.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Luego se asocia la política de permisos previamente creada:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dTPZo9DZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513430760/2DYsrNga1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dTPZo9DZ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513430760/2DYsrNga1.png" alt="image-7.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Luego se adicionan los tags al rol:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ote0G3X1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513447101/ePRyTEC98.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ote0G3X1--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513447101/ePRyTEC98.png" alt="image-8.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finalmente se verifica que este bien creado el rol, se le asigna un nombre y una descripción:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hTdttkiX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513460287/N_TDW4RtF.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hTdttkiX--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513460287/N_TDW4RtF.png" alt="image-9.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Una vez creado el rol se verifica que este contenga la relación de confianza con S3 Batch Operations:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xkAzKUbL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513473283/ci0-5Gv3P.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xkAzKUbL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513473283/ci0-5Gv3P.png" alt="image-10.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ykZKh1uU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513487745/0GufARKuz.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ykZKh1uU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513487745/0GufARKuz.png" alt="image-11.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id="batch-ops-conf"&gt;Configuración de S3 Batch Operation&lt;/h2&gt;

&lt;p&gt;Ingresar a Amazon S3 y en el menú seleccionar Batch Operations:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OG5nTTix--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513503900/sh0NMTlfj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OG5nTTix--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513503900/sh0NMTlfj.png" alt="image-12.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Luego Crear Job:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--C9d0U7Ou--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513520855/7WpHRQ0aQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--C9d0U7Ou--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513520855/7WpHRQ0aQ.png" alt="image-13.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;La creación del job se compone de 4 pasos:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Escoger la región y el archivo manifiesto con el listado de objetos.&lt;/li&gt;
&lt;li&gt;Escoger la operación por lote a realizar.&lt;/li&gt;
&lt;li&gt;Configuraciones adicionales.&lt;/li&gt;
&lt;li&gt;Verificación.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Se escoge la región donde se quiere crear el job. Para todas las operaciones, excepto para la de copia, se debe escoger la misma región donde se encuentran almacenados los objetos del listado. Para la operación de copia el Job se debe crear en la misma región donde se encuentra el bucket destino.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Pa2ZPqQr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513542949/qnIzmMt5k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Pa2ZPqQr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513542949/qnIzmMt5k.png" alt="image-14.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Luego se debe elegir el manifiesto (JSON) donde se referencia el listado de los objetos, este manifiesto es un archivo que se genera con el reporte de la funcionalidad &lt;em&gt;&lt;a href="https://juanc4milo.dev/inventario-aws-s3/"&gt;Inventario de AWS S3&lt;/a&gt;&lt;/em&gt;. También se puede seleccionar un archivo en formato CSV, que debe tener la estructura &lt;code&gt;BucketName, ObjectKey&lt;/code&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HPbG2h62--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513592245/cfuHu7i57.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HPbG2h62--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513592245/cfuHu7i57.png" alt="image-16.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Luego se selecciona la operación que se quiere ejecutar en el job. Para este caso del ejemplo, la idea es copiar los archivos entre 2 buckets, para ello, se selecciona “Copia”:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--m2yOLTk0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513608207/jGFaUlwE1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--m2yOLTk0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513608207/jGFaUlwE1.png" alt="image-17.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Como se ha elegido copia, saldrán las opciones de configuración para llevar a cabo esta tarea. Se solicita indicar el bucket destino donde serán copiados los objetos. AWS advierte que si no se tiene habilitado el &lt;em&gt;Versioning &lt;/em&gt;en el bucket destino, si llega a encontrar un objeto similar durante la copia, este será sobreescrito.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--2XsAOjOU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513622457/rTNBiSz4m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--2XsAOjOU--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513622457/rTNBiSz4m.png" alt="image-18.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Luego se debe seleccionar el tipo de almacenamiento que serán copiado los archivos en el bucket destino.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ctPoPb-d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513635115/wOymQ20Fl.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ctPoPb-d--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513635115/wOymQ20Fl.png" alt="image-19.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Luego se debe indicar si los datos se deben proteger con encripción en reposo usando SSE-S3 o AWS KMS:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--8PQGNpGP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513647864/aiuHmW9zP.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--8PQGNpGP--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513647864/aiuHmW9zP.png" alt="image-20.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Luego se debe indicar qué se debe hacer con los tags de los objetos durante la copia:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Copiar los mismos tags existentes de cada objeto.&lt;/li&gt;
&lt;li&gt;Reemplazar todos los tags por otros.&lt;/li&gt;
&lt;li&gt;No copiar ningún tag.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TpdTE10l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513662586/O2b0uXlRq.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TpdTE10l--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513662586/O2b0uXlRq.png" alt="image-21.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Luego se debe indicar qué se debe hacer con la metadata de los objetos durante la copia:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Copiar la misma metadata existente de cada objeto.&lt;/li&gt;
&lt;li&gt;Reemplazar toda la metadata con otros valores.&lt;/li&gt;
&lt;li&gt;No copiar ningún valor de metadata.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TNKjHgpM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513676718/Boy0Azl_z.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TNKjHgpM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513676718/Boy0Azl_z.png" alt="image-22.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Luego se debe seleccionar los permisos de la lista de control de acceso para cada objeto (permiso de los objetos):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Tu5rMmU8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513689773/InrzayUow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Tu5rMmU8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513689773/InrzayUow.png" alt="image-23.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Luego se debe asignar una descripción (nombre) al job y una prioridad (en números):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Repni8M6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513703421/M8eHagfKk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Repni8M6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513703421/M8eHagfKk.png" alt="image-24.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Luego se debe indicar si se requiere que el Job genere un reporte con el estado de la ejecución de las operaciones por cada uno de los objetos. En caso que si se quiera la generación del reporte, se debe indicar el bucket donde será almacenado el archivo.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TL1cJfPL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513715473/PfOsSgND5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TL1cJfPL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513715473/PfOsSgND5.png" alt="image-25.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Luego se deben asignar los permisos para el Job. Para ello se debe seleccionar el IAM Rol creado previamente que contiene la política de permisos sobre los recursos que va a usar S3 Batch Operations.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--on-0BqwR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513729189/wnk5T6ERv.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--on-0BqwR--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513729189/wnk5T6ERv.png" alt="image-26.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Finalmente se verifica todas las configuraciones realizadas anteriormente para revisar que todo esté en orden y al final se da click sobre Crear Job.&lt;/p&gt;

&lt;p&gt;Una vez creado el Job, Amazon advierte que va a verificar el manifiesto (o archivo CSV) que contiene el listado de objetos al que se le va a aplicar las operaciones por lotes. Si todo se encuentra en orden, pasa el estado del Job de “&lt;em&gt;Nuevo&lt;/em&gt;” a “&lt;em&gt;En espera por ejecución&lt;/em&gt;”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--78wykpWJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513746133/Dic2F555D.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--78wykpWJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513746133/Dic2F555D.png" alt="image-27.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Amazon entrega un ID para el Job creado e indica que los Jobs se borran automáticamente luego de 90 días así se hayan terminado OK o en ERROR.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--S-rcwsfA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513758584/6j2PKWUgr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--S-rcwsfA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513758584/6j2PKWUgr.png" alt="image-28.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZRincWmc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513768934/mai4jva7k.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZRincWmc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513768934/mai4jva7k.png" alt="image-29.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Una vez que Amazon haya terminado de verificar el Job, lo pasa al estado “&lt;em&gt;Pendiente por ejecución&lt;/em&gt;” y es aquí donde se puede seleccinar el Job y dar click en “&lt;em&gt;Ejecutar&lt;/em&gt;” (Run):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--wY36t597--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513782555/SiqYcB64T.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--wY36t597--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513782555/SiqYcB64T.png" alt="image-30.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Cuando se da click en &lt;em&gt;Run Job&lt;/em&gt;, muestra nuevamente toda la configuración del job para estar seguros de lo que se va a ejecutar. Al final aparece el botón Run Job para iniciar con la ejecución de la tarea:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--72UJhmHb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513794706/2NDuKP55b.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--72UJhmHb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513794706/2NDuKP55b.png" alt="image-31.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Una vez completado, lo pasa a un estado “&lt;em&gt;Completado&lt;/em&gt;”, indicando el 100% de la tarea completada y el % de errores (si los hubiese).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EjD_buw3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513807769/2dz88Zdvd.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EjD_buw3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603513807769/2dz88Zdvd.png" alt="image-32.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2 id="batch-ops-pricing"&gt;Costos&lt;/h2&gt;

&lt;p&gt;En cuanto a costo por usar esta funcionalidad, están las siguientes cifras:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Por cada job&lt;/strong&gt; que se cree en S3 Batch Operation incurrirá en un costo de $0,25 USD.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Por cada millón de operaciones&lt;/strong&gt; realizada sobre los objetos incurre en un costo de $1,00 USD.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Esto quiere decir, que es muy importante definir bien la creación del job, debido a que durante el proceso de su creación si hemos cometido algún error (falta de permisos en el rol, falta de permisos en las políticas, elección de un inventario de objetos que no corresponde, etc.), nos cobran igualmente por crear un job que esté errado en su ejecución.&lt;/p&gt;

&lt;p&gt;Por otra parte, se nota el gran beneficio el usar esta funcionalidad, ya que por realizar por ejemplo un copiado de 1 millón de archivos entre 2 buckets, solo nos cobra $1 USD.&lt;/p&gt;

&lt;h3&gt;
  
  
  Otros artículos que te podrían interesar...
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/redis-instalacion-y-configuracion"&gt;Redis - Instalación y Configuración&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/inventario-aws-s3"&gt;AWS S3 Inventory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/aws-elasticache"&gt;Qué ofrece y cómo se configura AWS Elasticache?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/aws-elasticache"&gt;Qué ofrece y cómo se configura Elasticache en AWS?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt; &lt;a href="https://juanc4milo.dev/redis-with-spring-in-java"&gt;How to use Redis with Spring in Java&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Do you like it?&lt;/strong&gt; You can &lt;a href="https://buymeacoffee.com/juanc4milo"&gt;buy me a beer&lt;/a&gt; if you want.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://juanc4milo.dev"&gt;juanc4milo.dev&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>aws</category>
      <category>s3</category>
      <category>batch</category>
      <category>storage</category>
    </item>
    <item>
      <title>Inventario AWS S3</title>
      <dc:creator>juanc4milo</dc:creator>
      <pubDate>Sun, 25 Oct 2020 23:48:13 +0000</pubDate>
      <link>https://dev.to/juanc4milo/inventario-aws-s3-1765</link>
      <guid>https://dev.to/juanc4milo/inventario-aws-s3-1765</guid>
      <description>&lt;h2&gt;
  
  
  AWS S3 Inventory
&lt;/h2&gt;

&lt;p&gt;En ocasiones cuando tenemos un repositorio de documentos con miles o millones de objetos, como por ejemplo AWS S3, Google Cloud Storage o Azure Blob Storage, es probable que perdamos la noción de todo lo que se tiene almacenado en ese repositorio.&lt;/p&gt;

&lt;p&gt;Para ello, en el caso de AWS, se dispone de una funcionalidad llamada Inventory, la cual nos permite generar un listado de todos los archivos alojados en determinada ubicación y sobre ese listado incluir ciertos parámetros que nos permite obtener más información sobre lo que tenemos almacenado.&lt;/p&gt;

&lt;p&gt;Este listado  de inventario de objetos (archivos) en el bucket S3 de Amazon, se puede generar por medio de esta funcionalidad &lt;em&gt;Inventory &lt;/em&gt;(Inventario) la cual por defecto nos genera un archivo en formato CSV con la siguiente estructura:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;BucketName, KeyObject&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Para generar este listado, se ingresa al servicio de S3 en la consola de AWS, se selecciona el bucket donde se encuentras los objetos que queremos listar, luego se selecciona &lt;em&gt;Management&lt;/em&gt; y luego &lt;em&gt;Inventory&lt;/em&gt;:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---wedO1wA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603487893090/4NuAeNRCS.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---wedO1wA--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603487893090/4NuAeNRCS.png" alt="image-1.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Una vez ubicados en este punto, se puede elegir adicionar una nueva tarea de generación de listado de inventario de nuestros objetos:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4wybrFKd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603488004961/Lm32koOke.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4wybrFKd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603488004961/Lm32koOke.png" alt="image-13.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Al seleccionar la opción de crear una nueva tarea de creación de inventario, la página nos solicita los siguientes campos:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Inventory name&lt;/strong&gt;: Nombre de la tarea de inventario.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Filters&lt;/strong&gt;: Prefijo S3 desde donde se va a generar el listado de objetos (carpeta desde donde se requiere el listado de archivos).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Destination Bucket&lt;/strong&gt;: Nombre del bucket donde se quiere crear el listado.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Destination Prefix&lt;/strong&gt;: Prefijo donde se quiere crear el listado.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Frequency&lt;/strong&gt;: Frecuencia con la que se quiere generar el reporte (diaria o semanal).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--L-E7flK9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603488068367/_ofP6Jx_h.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--L-E7flK9--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603488068367/_ofP6Jx_h.png" alt="image-3.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;En opciones avanzadas se puede seleccionar lo siguiente:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Output format&lt;/strong&gt;: Formato de salida del listado. El formato puede ser: CSV, Apache ORC, Apache Parquet.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Object versions&lt;/strong&gt;: Seleccionar si quiere el listado solo con las versiones actuales del objeto o con todas las versiones (si se tiene habilitado el versioning).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Optional fields&lt;/strong&gt;: Campos adicionales que va a contener el reporte. Por defecto está: NombreBucket y KeyObject.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Encryption&lt;/strong&gt;: Método de encripción para el listado de objetos. Puede ser Ninguno, AES-256, AWS-KMS.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tzevelT2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603488101510/MPYayAUlw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tzevelT2--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603488101510/MPYayAUlw.png" alt="image-4.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Una vez diligenciado todos los campos, se debe ver algo como lo siguiente:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fZKUAQZl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603488120866/M8WwFX0uX.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fZKUAQZl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603488120866/M8WwFX0uX.png" alt="image-5.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Amazon advierte que el primer reporte de listado de objetos, podría tardar en generarse 48 horas, aunque, dependiendo de la cantidad de objetos que debe listar en el reporte, podría tomar mucho menos tiempo. Para este caso que solo se ha seleccionado generar la carpeta de un cliente (200 objetos), el reporte se generó en 24 horas.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--H4vc_JWe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603488141937/XqjU6joLY.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--H4vc_JWe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603488141937/XqjU6joLY.png" alt="image-6.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Adicional, al crear la tarea de generación de reporte de inventario, Amazon automáticamente crea una política de Bucket para tener permisos de escritura sobre el bucket seleccionado para la entrega del listado.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RFs-jJfa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603488171067/F5AZrLl-F.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RFs-jJfa--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603488171067/F5AZrLl-F.png" alt="image-7.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;pre&gt;{
    "Sid": "S3PolicyStmt-DO-NOT-MODIFY-160xxxxxxxxxx",
    "Effect": "Allow",
    "Principal": {
        "Service": "s3.amazonaws.com"
    },
    "Action": [
        "s3:PutObject"
    ],
    "Resource": [
        "arn:aws:s3:::prueba-de-copiado-de-inventory-job/*"
    ],
    "Condition": {
        "ArnLike": {
            "aws:SourceArn": [
                "arn:aws:s3:::prueba-de-copiado-de-inventory-job"
            ]
        },
        "StringEquals": {
            "aws:SourceAccount": [
                "97xxxxxxxxx"
            ],
            "s3:x-amz-acl": "bucket-owner-full-control"
        }
    }
}&lt;/pre&gt;

&lt;p&gt;Una vez transcurridas las primeras 24 horas a partir de que se crea la tarea de generación del listado de objetos, en el bucket se puede observar que se crea una carpeta donde se ubica el reporte:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OP0RR8Ux--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603488201105/mc9tMhNhp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OP0RR8Ux--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603488201105/mc9tMhNhp.png" alt="image-8.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Una vez ingresado en el prefijo donde se indicó que debía ubicar los reportes diarios, aparecerán 3 carpetas inicialmente. Para el caso de la imagen anterior, las carpetas adicionales nombradas por una fecha, corresponde a los días de generación del reporte, en este casi diario.&lt;/p&gt;

&lt;p&gt;La primer carpeta con la &lt;em&gt;fecha de generación&lt;/em&gt; del reporte, contiene el manifiesto de generación del reporte en formato .json. Este manifiesto alberga la metadata del archivo de inventario generado por AWS, que nos indica fecha de generación, ubicación del reporte, tamaño, extensión, etc.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4dKb4y-W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603488229122/w11wiKnOb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4dKb4y-W--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603488229122/w11wiKnOb.png" alt="image-10.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;pre&gt;{
  "sourceBucket" : "prueba-de-copiado-de-inventory-job",
  "destinationBucket" : "arn:aws:s3:::prueba-de-copiado-de-inventory-job",
  "version" : "2016-11-30",
  "creationTimestamp" : "1581379200000",
  "fileFormat" : "CSV",
  "fileSchema" : "Bucket, Key",
  "files" : [ {
    "key" : "prueba-de-copiado-de-inventory-job/data/6fbf1c72-aded-47ff-91e4-2448addfd5a5.csv.gz",
    "size" : 127,
    "MD5checksum" : "60aee2df4caf7f4b00a7375bc978d1c8"
  } ]
}&lt;/pre&gt;

&lt;p&gt;La segunda carpeta, &lt;em&gt;data&lt;/em&gt; contiene el archivo de reporte en formato CSV con todo el listado de los documentos ubicados en la ruta que se haya especificado para listar los objetos.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TCbjHrUb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603488250875/R_eoJxIJR.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TCbjHrUb--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603488250875/R_eoJxIJR.png" alt="image-11.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;La tercer carpeta, &lt;em&gt;hive&lt;/em&gt; con un archivo de texto que contiene la URL completa de donde está ubicado el reporte en nuestro bucket.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_l6W8O2u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603488270349/TAJpB9Dvb.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_l6W8O2u--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn.hashnode.com/res/hashnode/image/upload/v1603488270349/TAJpB9Dvb.png" alt="image-12.png"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Como se puede apreciar, la funcionalidad de AWS S3 Inventory nos permite generar un listado de todos los objetos y es de gran ayuda cuando tenemos millones de archivos en él. Adicional, estos listados son indispensables para automatizar procesos sobre estos objetos, como por ejemplo tareas de copiado de archivos entre buckets, cambiar el tipo de almacenamiento, cambiar la metadata o los tags de los objetos, entre otros. &lt;/p&gt;

&lt;p&gt;Un dato adicional a tener en cuenta es que esta funcionalidad tiene un costo que oscila entre los $0,0025 USD y $0,0035 USD por millón de objetos enumerados, dependiendo de la región donde se realice la ejecución del inventario. También, los archivos resultantes como los manifiestos y la data (archivos CSV) almacenados en el bucket, deben incurrir en los costos asociados de solicitudes sobre el bucket de estos objetos y en el tamaño/tiempo de almacenamiento.&lt;/p&gt;

&lt;p&gt;Toda esta configuración que hemos visto por medio de la consola web de AWS, se puede realizar a través de la herramienta de línea de comando AWS cli, usando el comando &lt;code&gt;put-bucket-inventory-configuration&lt;/code&gt;. Para más detalle se puede revisar la documentación en su sitio web oficial &lt;a rel="noreferrer noopener" href="https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3api/put-bucket-inventory-configuration.html"&gt;https://awscli.amazonaws.com/v2/documentation/api/latest/reference/s3api/put-bucket-inventory-configuration.html&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;De igual forma, se puede realizar por medio del AWS SDK disponible para todos los lenguajes de programación soportados por Amazon, el cual se puede ver mayor detalle en su documentación: &lt;a rel="noreferrer noopener" href="https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketInventoryConfiguration.html"&gt;https://docs.aws.amazon.com/AmazonS3/latest/API/API_PutBucketInventoryConfiguration.html&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Otros artículos que te podrían interesar...
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/redis-instalacion-y-configuracion"&gt;Redis - Instalación y Configuración&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/aws-s3-batch-operations"&gt;AWS S3 Batch Operations&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/aws-elasticache"&gt;Qué ofrece y cómo se configura AWS Elasticache?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://juanc4milo.dev/aws-elasticache"&gt;Qué ofrece y cómo se configura Elasticache en AWS?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt; &lt;a href="https://juanc4milo.dev/redis-with-spring-in-java"&gt;How to use Redis with Spring in Java&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Do you like it?&lt;/strong&gt; You can &lt;a href="https://buymeacoffee.com/juanc4milo"&gt;buy me a beer&lt;/a&gt; if you want.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;Originally published at &lt;a href="https://juanc4milo.dev"&gt;juanc4milo.dev&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

</description>
      <category>aws</category>
      <category>s3</category>
      <category>inventory</category>
      <category>storage</category>
    </item>
  </channel>
</rss>
