Acme-CPANModulesBundle-Import-PerlDancerAdvent-2018

 view release on metacpan or  search on metacpan

META.json  view on Meta::CPAN

         },
         {
            "class" : "Dist::Zilla::Plugin::ShareDir",
            "name" : "@Author::PERLANCAR/@Filter/ShareDir",
            "version" : "6.010"
         },
         {
            "class" : "Dist::Zilla::Plugin::MakeMaker",
            "config" : {
               "Dist::Zilla::Role::TestRunner" : {
                  "default_jobs" : 1
               }
            },
            "name" : "@Author::PERLANCAR/@Filter/MakeMaker",
            "version" : "6.010"
         },
         {
            "class" : "Dist::Zilla::Plugin::Manifest",
            "name" : "@Author::PERLANCAR/@Filter/Manifest",
            "version" : "6.010"
         },

META.yml  view on Meta::CPAN

      name: '@Author::PERLANCAR/@Filter/ExecDir'
      version: '6.010'
    -
      class: Dist::Zilla::Plugin::ShareDir
      name: '@Author::PERLANCAR/@Filter/ShareDir'
      version: '6.010'
    -
      class: Dist::Zilla::Plugin::MakeMaker
      config:
        Dist::Zilla::Role::TestRunner:
          default_jobs: 1
      name: '@Author::PERLANCAR/@Filter/MakeMaker'
      version: '6.010'
    -
      class: Dist::Zilla::Plugin::Manifest
      name: '@Author::PERLANCAR/@Filter/Manifest'
      version: '6.010'
    -
      class: Dist::Zilla::Plugin::ConfirmRelease
      name: '@Author::PERLANCAR/@Filter/ConfirmRelease'
      version: '6.010'

devdata/http_advent.perldancer.org_2018_13  view on Meta::CPAN

<h3><a name="websockets"></a>Websockets</h3>

<p>You asked, and Yanick delivered! <a href="https://metacpan.org/pod/Dancer2::Plugin::WebSocket">Dancer2::Plugin::Websocket</a>
enables websockets from within your Dancer2 applications. To make this work
properly, a non-blocking, streaming Plack server is needed (such as Twiggy).</p>
<h3><a name="mutable_serializer"></a>Mutable Serializer</h3>

<p>Dancer2 can now properly deserialize and serialize content based upon the 
request headers. Even better, it's completely and easily configurable! Thanks
to veryrusty for spearheading the effort to get this working!</p>
<h3><a name="no_default_middleware"></a>No Default Middleware</h3>

<p>To support ETags and other similar features, the default Plack middleware used
by Dancer2 can get in the way. To get around this, veryrusty added a 
<code>no_default_middleware</code> configuration option to Dancer2's <i>config.yml</i> file
to keep your application from using the default bundling of Plack middleware.</p>
<h2><a name="better_documentation"></a>Better Documentation</h2>

<p>Several dozen bug fixes, clarifications, and other enhancements have been made
to the documentation, primarily by the Dancer2 community. As a result, the 
quality of existing docs has been greatly improved.</p>
<p>Several new examples have been added to both the Dancer2 distribution as well
as the tutorial.</p>
<p>Sawyer has started a significant project to rebuild the Dancer2 documentation 
from scratch. The current docs lack a good description of why Dancer does 
things a certain way, and doesn't give new users a good grounding in web 

devdata/http_advent.perldancer.org_2018_16  view on Meta::CPAN

use Moose;
use Minion;

use MyJob::Models::FooBar;
with 'MyJob::Roles::ConfigReader';

has 'runner' =&gt; (
    is      =&gt; 'ro',
    isa     =&gt; 'Minion',
    lazy    =&gt; 1,
    default =&gt; sub( $self ) {
        $ENV{ MOJO_PUBSUB_EXPERIMENTAL } = 1;
        Minion-&gt;new( mysql =&gt; 
          MyJob::DBConnectionManager-&gt;new-&gt;get_connection_uri({ 
            db_type =&gt; 'feeds', 
            io_type =&gt; 'rw',
        }));
    },
);</pre>

<p>We wrapped a simple Moose class around Minion to make it easy to add to any class or Dancer application with the extra functionality we wanted.</p>
<p>We ran into an issue at one point where jobs weren't running since we added them to a queue that no worker was configured to handle. To prevent this from happening to us again,
we added code to prevent us from adding code to a queue that didn't exist:</p>
<pre class="prettyprint">my @QUEUE_TYPES = qw( default InstantXML PayrollXML ChangeRequest );

sub has_invalid_queues( $self, @queues ) {
    return 1 if $self-&gt;get_invalid_queues( @queues );
    return 0;
}

sub get_invalid_queues( $self, @queues ) {
    my %queue_map;
    @queue_map{ @QUEUE_TYPES } = (); 
    my @invalid_queues = grep !exists $queue_map{ $_ }, @queues;
    return @invalid_queues;
}</pre>

<p>With that in place, it was easy for our <code>queue_job()</code> method to throw an error if the developer tried to add a job to an invalid queue:</p>
<pre class="prettyprint">sub queue_job( $self, $args ) {
    my $job_name = $args-&gt;{ name     } or die "queue_job(): must define job name!";
    my $guid     = $args-&gt;{ guid     } or die "queue_job(): must have GUID to process!";
    my $title    = $args-&gt;{ title    } // $job_name;
    my $queue    = $args-&gt;{ queue    } // 'default';
    my $job_args = $args-&gt;{ job_args };

    die "queue_job(): Invalid job queue '$queue' specified" 
        if $self-&gt;has_invalid_queues( $queue );

    my %notes = ( title =&gt; $title, guid  =&gt; $guid );

    return $self-&gt;runner-&gt;enqueue( $job_name =&gt; $job_args =&gt; 
        { notes =&gt; \%notes, queue =&gt; $queue });
}</pre>

<h2><a name="creating_jobs"></a>Creating Jobs</h2>

<p>In our base model class (Moose-based), we would create an attribute for our job runner:</p>
<pre class="prettyprint">has 'job_runner' =&gt; (
    is      =&gt; 'ro',
    isa     =&gt; 'MyJob::JobQueue',
    lazy    =&gt; 1,
    default =&gt; sub( $self ) { return MyJob::JobQueue-&gt;new-&gt;runner; },
);</pre>

<p>And in the models themselves, creating a new queueable task was as easy as:</p>
<pre class="prettyprint">$self-&gt;runner-&gt;add_task( InstantXML =&gt; 
    sub( $job, $request_path, $guid, $company_db, $force, $die_on_error = 0 ) {
        $job-&gt;note( 
            request_path =&gt; $request_path,
            feed_id      =&gt; 2098,
            group        =&gt; $company_db,
        );

devdata/http_advent.perldancer.org_2018_16  view on Meta::CPAN

<p>We wanted to easily configure our Minions for all hosts and environments in one spot. Since we use a lot of YAML in Dancer, specifying the Minion configuration in YAML made a lot of sense
to us:</p>
<pre class="prettyprint"># What port does the dashboard listen on?
dashboard_port: 4000

# Add the rest later.
dashboards:
    UNKNOWN: http://localhost:3000/
    DEV: http://my.development.host.tld:8001/

# Hosts that have no entry assume the default configuration
default:
    max_children: 4
    queues:
        - default

# Host-specific settings
jcrome-precision-3510:
    max_children: 8
    queues:
        - default
        - InstantXML
        - PayrollXML
        - ChangeRequest</pre>

<p>Our job queue workers look like:</p>
<pre class="prettyprint">#!/usr/bin/env perl

use MyJob::Base;
use MyJob::JobQueue;
use MyJob::Log4p;

devdata/http_advent.perldancer.org_2018_16  view on Meta::CPAN

<p>Remember the YAML file we used to configure things up above? This last bit pulls the information for the host this worker is running on (<code>get_hostname()</code> is a home-grown 
hostname function):</p>
<pre class="prettyprint">sub get_hostconfig {
    my $minion_config = 
        MyJob::Config-&gt;new({ filename =&gt; "environments/minions.yml" })-&gt;config;
    my $hostname      = get_hostname();

    if( exists $minion_config-&gt;{ $hostname }) {
        return $minion_config-&gt;{ $hostname };
    } else {
        return $minion_config-&gt;{ default };
    }
}</pre>

<h2><a name="monitoring_the_workers"></a>Monitoring the Workers</h2>

<p>Our Minion dashboard was virtually identical to the one that @preaction posted in <a href="https://mojolicious.io/blog/2018/12/11/who-watches-the-minions/#section-2">Who Watches the Minions?</a>.
If you'd like to know more, I highly recommend reading his article.</p>
<h2><a name="outcome"></a>Outcome</h2>

<p>Within about a two-week timespan, we went from having zero practical knowledge of Minion to having things up and running. We've made some refinements and improvements along the way, but the quick turnaround

devdata/http_advent.perldancer.org_2018_17  view on Meta::CPAN

</li>
</ul>
</div>


<div id="content">
<div class="pod-document"><h1><a name="dancer_and_email"></a>Dancer and Email</h1>

<p>Web applications regularly need to send email to its users, e.g. receipts or password reset links. 
The <a href="https://metacpan.org/pod/Dancer2::Plugin::Email">Email</a> plugin for Dancer2 simplifies this task by
providing the <code>email</code> keyword and a sane default configuration.</p>
<p>So the unavoidable "Hello world" example would look like:</p>
<pre class="prettyprint">email {
    from =&gt; 'foo@perl.dance',
    to =&gt; 'bar@perl.dance',
    subject =&gt; 'Hello world',
    text =&gt; 'Welcome to the dancefloor!',
};</pre>

<p>The more common case would be to use a template from your web application and turn it into a HTML email.</p>
<p>Instead of using the <code>template</code> keyword to return the HTML from your route to the browser, you generate HTML with a specific layout,

devdata/http_advent.perldancer.org_2018_18  view on Meta::CPAN

Dancer2 application skeleton without having to write it yourself.</p>
<p>For example, creating an app called <code>My::Web::App</code>, you can run the following:</p>
<pre class="prettyprint">dancer2 gen -a My::Web::App</pre>

<p>The <code>dancer2</code> command line has a few more options, which you can see, if
you run <code>dancer2 gen --help</code>.</p>
<h2><a name="changing_the_skeleton"></a>Changing the skeleton</h2>

<p>Dancer2 generates a skeleton that it useful for most developers, but if
you are a seasoned Dancer2 developer, you might have a set of
preferences not represented in the default skeleton.</p>
<p>If it's different file setup that you want to have, you could partially
achieve it with the <code>dancer2 gen -s DIRECTORY</code>, indicating a different
skeleton directory. But that doesn't fix all of it.</p>
<p>To have full control over the entire scaffolding operation, you will
need to have control of the command line implementation. Let me show
you how.</p>
<h2><a name="extending_in_a_class"></a>Extending in a class</h2>

<p>To extend the application in a class, you will need to write a new
class with a new command. That class will then need to be loaded in your

devdata/http_advent.perldancer.org_2018_18  view on Meta::CPAN

environment variable), you will be able to run the following:</p>
<pre class="prettyprint">$ dancer2 activate --directory foo/</pre>

<p>(The implementation of what "activation" means in this context is left
to the reader.)</p>
<p>But what if you want to provide an alteration of an existing command -
the generation of the Dancer2 application?</p>
<h3><a name="writing_a_new_command"></a>Writing a new command</h3>

<p>Let's say you have a set of adjustments you keep doing to your
[company's] Dancer2 applications and you want to make these a default.</p>
<p>You can write it as a new command or you can subclass the existing
command and do whatever alterations you want before, during, and after
the generation of the skeleton.</p>
<pre class="prettyprint">package Dancer2::CLI::Command::mygen;
use strict;
use warnings;
use Cwd (); # Our own dependencies

# Subclass the existing "gen" command
use parent 'Dancer2::CLI::Command::gen';

devdata/http_advent.perldancer.org_2018_18  view on Meta::CPAN

  # Now we finished generating, but we can contineu customizing what we have
}

1;</pre>

<p>Writing your own generation on top of the existing generation allows
you to manage the input (including additional validation) and the
output, giving you full control over the scaffolding process.</p>
<p>Some examples on which customizations you might want to perform:</p>
<ul>
<li><a name="item_Add_additional_default_imported_classes"></a><b>Add additional default imported classes</b>
</li>
<li><a name="item_Change_the_output_directory_name"></a><b>Change the output directory name</b>
</li>
<li><a name="item_Update_a_database_that_we_have_a_new_application"></a><b>Update a database that we have a new application</b>
</li>
<li><a name="item_Update_your_team_with_an_email_or_IRC_Slack_message"></a><b>Update your team with an email or IRC/Slack message</b>
</li>
<li><a name="item_Remove_files_that_are_not_applicable_for_your_setup_and_add_new_ones"></a><b>Remove files that are not applicable for your setup and add new ones</b>
</li>
<li><a name="item_Write_helpful_output_for_the_developer_who_scaffolded_the_app"></a><b>Write helpful output for the developer who scaffolded the app</b>

devdata/http_advent.perldancer.org_2018_19  view on Meta::CPAN

<p>Now, restart your application, and visit a route that has logging installed, and you will see your log
message not only goes to the <i>logs/mylog.log</i> file, but also displays on the console running your
application. Easy!</p>
<h2><a name="some_gotchas"></a>Some Gotchas</h2>

<p>There are a couple of important nuances you should be aware of:</p>
<ul>
<li><a name="item_Environment_configuration_replaces_logging_configuration"></a><b>Environment configuration replaces logging configuration</b>
<p>If you put your logging configuration in <i>config.yml</i> rather than one of your environment-specific
configuration files (such as <i>environments/development.yml</i>), you stand a good chance of not using
the logging configuration you think you are using. The default configuration file for the development
environment, for example, logs only to the console. If you put your Log4perl configuration in <i>config.yml</i>
and don't change your development configuration file, your Log4perl configuration will be passed over
for the default console logger.</p>
<p>From my own experience, <b>always</b> configure your logger in your environment-specific configuration, unless
you use the same configuration across all environments (I don't endorse this practice).</p>
</li>
<li><a name="item_Core_level_messages_are_passed_as_log_level_trace__but_will_not_be_passed_unless_Dancer2_s_log_level_is_core_"></a><b>Core level messages are passed as log level trace, but will not be passed unless Dancer2's log level is core.</b>
<p>Since <code>core</code> doesn't have a good corresponding level in Log4perl, <code>core</code> level messages are sent 
over to Log4perl at the <code>trace</code> log level. This <b>only</b> happens when you set Dancer2's log level in your
<i>config.yml</i> file to <code>core</code> however. So your preferred log level setting is respected, even if <code>core</code> level 
messages have to be reported at a different level.</p>
</li>
<li><a name="item__code_log__code__should_be_set_a_lower_priority_than_the_lowest_priority_as_set_in_your_Log4perl_configuration_"></a><b><code>log</code> should be set a lower priority than the lowest priority as set in your Log4perl configuration.<...

devdata/http_advent.perldancer.org_2018_22  view on Meta::CPAN

    'optional' =&gt; [ 'body', 'sid', 'SHA1' ],
] =&gt; sub {...};</pre>

<p>In this form, the parameter <code>format</code> can be provided either in the
query string or in the body, because your route might be either a
<b>GET</b> or a <b>POST</b>.</p>
<h3><a name="register_type_actions"></a>Register type actions</h3>

<p>Type checking itself is the main role of this plugin, but you can also
control how it behaves.</p>
<p>The default action to perform when a type check fails is to error out,
but you can decide to act differently by registering a different
action.</p>
<pre class="prettyprint">register_type_action 'SoftError' =&gt; sub {
    my ( $self, $details ) = @_;

    warning "Parameter $details-&gt;{'name'} from $details-&gt;{'source'} "
          . "failed checking for type $details-&gt;{'type'}, called "
          . "action $details-&gt;{'action'}";

    return;

devdata/http_advent.perldancer.org_2018_23  view on Meta::CPAN

</ul>
</div>


<div id="content">
<div class="pod-document"><h1><a name="dancer2__logger__console__colored"></a>Dancer2::Logger::Console::Colored</h1>

<p>During development the console output of your app is often one of the most important tools.
But sometimes there is just too much noise, and changing the log settings all the time is not convenient.
Of course you can grep the log or scroll, but wouldn't it be nice to get visual clues for what you're looking for?</p>
<p>With <a href="https://metacpan.org/module/Dancer2::Logger::Console::Colored">Dancer2::Logger::Console::Colored</a> you can do that. It's a drop-in replacement for the default
console logger, but with color. It will make the message appear in color depending on the levels. You can turn
it on by setting your logger in your environment config file:</p>
<pre class="prettyprint">logger: "Console::Colored"</pre>

<p>Your log will instantly become cheerful and seasonal according to this default configuration:</p>
<pre class="prettyprint"># config.yml (these are the defaults)
engines:
  logger:
    Console::Colored:
      colored_origin: "cyan"
      colored_levels:
        core: "bold bright_white"
        debug: "bold bright_blue"
        info: "bold green"
        warning: "bold yellow"
        error: "bold yellow on_red"

devdata/http_advent.perldancer.org_2018_23  view on Meta::CPAN

<p>And the <code>colored_messages</code> refer to the actual message.</p>
<pre class="prettyprint">[main:28764] debug @2018-12-19 20:31:06&gt; Hello World in test.pl l. 6
                                         ^^^^^^^^^^^</pre>

<p>The colors are the same kind of color strings used by <a href="https://metacpan.org/module/Term::ANSIColor">Term::ANSIColor</a>. The first
color refers to the foreground, and the second one to the background. You can add an optional <code>bold</code>.</p>
<pre class="prettyprint">[bold] [foreground] [on_background]</pre>

<h2><a name="changing_the_log_message"></a>Changing the log message</h2>

<p>If you don't like the default log format, you can change it with the <code>log_format</code> setting, which is
documented in detail in <a href="https://metacpan.org/module/Dancer2::Core::Role::Logger">Dancer2::Core::Role::Logger</a>. You can just stick it in with the other configuration.</p>
<pre class="prettyprint"># config.yml (this is the default)
engines:
  logger:
    Console::Colored:
      log_format: "[%a:%P] %L @%T&gt; %m in %f l. %l"</pre>

<p>Usually you would run a single-worker server during development, so there is no need for request IDs.
And since the message is now colored, we can also drop the log level. How about a simple format like
the following:</p>
<pre class="prettyprint">%t %f:%l&gt; %m
# 20/Dec/2018 16:41:07 MyApp.pm:22&gt; Hello World</pre>



( run in 0.715 second using v1.01-cache-2.11-cpan-0a6323c29d9 )