Home Navigation

Thursday, 7 April 2022

Erlang cheatsheet

Erlang

Erlang is a programming language used to build massively scalable soft real-time systems with requirements on high availability. Some of its uses are in telecoms, banking, e-commerce, computer telephony and instant messaging. Erlang's runtime system has built-in support for concurrency, distribution and fault tolerance.


Installing erlang:

https://www.erlang-solutions.com/downloads/

https://tecadmin.net/install-erlang-on-centos/


Erlang basic syntax:
Compiling and running:
Start erlang shell just typing in the command line erl
Compile: >c(module_name).
Running: >module_name:function().

String concat:

> “earl” ++ “ang”. 
> string:concat(“erl” , “ang”).

 

Lists:

1> Insert = [2,4,5,6].
     [2,4,5,6]
2> Full = [1, Insert, 16,32].
     [1,[2,4,5,6],16,32]
3> Neat = lists:flatten(Full).
    [1,2,4,5,6,16,32]

Combine/merge:
> A = [1,3,5].
[1,3,5]
> B = [2,4,6].
[2,4,6]
> C = A ++ B.
[1,3,5,2,4,6]
> D = lists:append(A,B).
[1,3,5,2,4,6] 


Split by head and tail:
> [Head | Tail] = [1,2,4].
> Head.
1
> Tail.
[2,4]

Adding to a list:

> Y=[1,2 | [3]].
[1,2,3]
> Z=[1,2 | 3].
[1,2|3]

zip/unzip mixing list and tuples:

> List1=[1,2,4,8,16].
[1,2,4,8,16]
> List2=[a,b,c,d,e].
[a,b,c,d,e]
> TupleList=lists:zip(List1,List2).
[{1,a},{2,b},{4,c},{8,d},{16,e}]
> SeparateLists=lists:unzip(TupleList).
{[1,2,4,8,16],[a,b,c,d,e]}

Keystone/ key replace:

> Initial=[{1,tiger}, {3,bear}, {5,lion}].
[{1,tiger},{3,bear},{5,lion}]
> Second=lists:keystore(7,1,Initial,{7,panther}).
[{1,tiger},{3,bear},{5,lion},{7,panther}]
> Third=lists:keystore(7,1,Second,{7,leopard}).
[{1,tiger},{3,bear},{5,lion},{7,leopard}]
>Fourth=lists:keyreplace(6,1,Third,{6,chipmunk}).
 [{1,tiger},{3,bear},{5,lion},{7,leopard}]
> Animal5=lists:keyfind(5,1,Third).
{5,lion}
> Animal6=lists:keyfind(6,1,Third).
False

Higher-order functions, functions that accept other functions as arguments

lists:forach

1> Print = fun(Value) -> io:format("~p~n",[Value]) end.

#Fun<erl_eval.44.65746770>

2> List = [1,2,3,4,5,6].

[1,2,3,4,5,6]

3> lists:foreach(Print, List).

1

2

3

4

5

6

Ok


lists:map

> Square = fun(Value)->Value*Value end.

#Fun<erl_eval.44.65746770>

> lists:map(Square, List).

[1,4,9,16,25,36]

 

OR

> [Square(Value) || Value <- List].

> [Value * Value || Value <- List].

> List2 = [10 | List].                           

[10,1,2,3,4,5,6]

In list difference between | and || are, | concat and || map operation.

 

Filter:

> LessThanFive = fun(Value)-> (Value<5) and (Value>=0) end. 

#Fun<erl_eval.44.65746770>

> lists:filter(LessThanFive,List).                         

[1,2,3,4]

> [Value || Value <- List, Value<5, Value>=0].

[1,2,3,4]


> Weather = [{toronto, rain}, {montreal, storms}, {london, fog},  

> {paris, sun}, {boston, fog}, {vancouver, snow}].              

[{toronto,rain},

 {montreal,storms},

 {london,fog},

 {paris,sun},

 {boston,fog},

 {vancouver,snow}]

> 

> FoggyPlaces = [X || {X, fog} <- Weather].

[london,boston]


Maps:

ModuleSyntax
maps:new/1#{}
maps:put/3Map#{Key => Val}
maps:update/3Map#{Key := Val}
maps:get/2Map#{Key}
maps:find/2#{Key := Val} = Map


>Pets = #{"dog" => "al", "fish" => "dory"}.
>Pets#{"cat" => "tiger"}.
   #{"cat" => "tiger","dog" => "al","fish" => "dory"}
> Pets#{"dog":="Pok"}.
  #{"dog" => "Pok","fish" => "dory"}
> maps:get("dog", Pets).
"al"
> #{"fish" := CatName, "dog" := DogName} = Pets.
#{"dog" => "al","fish" => "dory"}

Process:

Sending message to a process using !

> self() ! test1.

test1 message will be waiting in the mail box

You can retrieve by receive block

> receive X -> X end.

 

Spawning a process:

> Pid=spawn(bounce,report,[]).

> Pid ! “Hello World”.

 

receive XXX -> XXX end.

exit(whereis(registered pid), kill).

flush().

erlang:process_info(self(), messages)

spawn(?ModuleName, <Function name> , <argument>)


Registrering a process:

register(<name to be registered> ,<Process id>).

whereis/1 to find the process

unregister/1. To unregister a process


Parent = ?current_span_ctx,

io:format("Parent: ~p~n",[Parent]),

Span2Ctx = Parent#span_ctx{trace_id=TraceId},

?set_current_span(Span2Ctx),


Record:

Records let you create data structures that use names to connect with data rather than order

For example

-record(planemo, {name, gravity, diameter, distance_from_sun}).

-record(tower, {location, height=20, planemo=earth, name}).


The command rr (for read records) lets you bring this into the shell:

 

1> rr("records.hrl").

[planemo,tower]

 

> Tower1=#tower{location="NYC", height=241, name="Woolworth Building"}.

 

Accessing value from a record

> Tower1#tower.planemo.

 

Pattern matching to extract value:

 

#tower{location=L5, height=H5} = Tower1.

 

Update record value:

 

Tower1a=Tower1#tower{height=512}.


ETS:

Erlang Term Storage (ETS) is a simple but powerful in-memory collection store.

 

Creating and Populating a Table

PlanemoTable=ets:new(planemos, [named_table, {keypos, #planemo.name}]),

ets:info(PlanemoTable).

 

To see what’s in the table

 

ets:tab2list(<record name eg, planemos>).

Lookup: ets:lookup(planemos,eris).

 

11> Result=hd(ets:lookup(planemos,eris)).

#planemo{name = eris,gravity = 0.8,diameter = 2400,

         distance_from_sun = 10210.0}

12> Result#planemo.gravity.

 

Overwriting Values

ets:insert(planemos, #planemo{ name=mercury,

 gravity=3.9, diameter=4878, distance_from_sun=57.9 }).

true

  

ets:fun2ms 

ets:match

ets:select

ets:delete

ets:first

ets:next

ets:last


Mnesia:

mnesia:create_schema([node()]).

mnesia:start().

mnesia:table_info/2


mnesia:transaction(fun() -> mnesia:read(planemo,neptune) end).

mnesia:first

mnesia:next

 

(If you want to change where Mnesia stores data, you can start Erlang with some extra options: erl -mnesia dir " path ". The path will be the location Mnesia keeps any disk-based storage.)

Apart from the setup, the key thing to note is that all of the writes are contained in a fun that is then passed to mnesia:transaction to be executed as a transaction. Mnesia will restart the transaction if there is other activity blocking it, so the code may get executed repeatedly before the transaction happens. Because of this, do not include any calls that create side effects to the function you’ll be passing to mnesia:transaction, and don’t try to catch exceptions on Mnesia functions within a transaction. If your function calls mnesia:abort/1 (probably because some condition for executing it wasn’t met), the transaction will be rolled back, returning a tuple beginning with aborted instead of atomic.


Query list:

 

mnesia:transaction(

  fun() ->

    qlc:e(

      qlc:q( [X || X <- mnesia:table(planemo)] )

    )

  end

) 

mnesia:transaction(

  fun() ->

    qlc:e(

      qlc:q( [{X#planemo.name, X#planemo.gravity} ||

               X <- mnesia:table(planemo),

               X#planemo.gravity < 9.8] )

    )

  end

)

mnesia:transaction(

  fun() ->

    qlc:e(

      qlc:q( [X || X <- mnesia:table(planemo),

                   X#planemo.gravity < 9.8] )

    )

  end

)


OTP

OTP is set of Erlang libraries and design principles providing middle-ware to develop these systems. It includes its own distributed database, applications to interface towards other languages, debugging and release handling tools.

 

OTP Gen server:

  • Generic server specific behaviour
  • Supports server like component 
  • business logic lives in app specific callback module

OTP formalizes those activities, and a few more, into a set of behaviors (or behaviours—this was originally created with British spelling). The most common behaviors are gen_server (generic server) and supervisor, though gen_fsm (finite state machine) and gen_event are also available. The application behavior lets you package your OTP code into a single runnable (and updatable) system.

 

OTP Building blocks:

  • process spawning
  • sending and receiving messages
  • process linking and monitoring

Application Behavior

  • application provides an entry point for an OTP-compliant app
  • Allows multiple Erlang components to be combined into a system
  • Erlang apps can declare their dependencies on other apps

Async Events

  • send_event: asynchronously send event into gen_fsm process
  • calls Module:StateName/2,where StateName is a function named for the current state
  • send_all_state_event: asynchronously send event into gen _fm process calls Module handle_event, allows handling event regardless of current state. current state name is passed into handle_event

Sync Events

  • sync _send_event: synchronously send event into gen_fsm process calls Module:StateName/3,where StateName is a function named for the current state
  • sync_send_all_state_event: synchronously send event into gen_fm process
  • calls Module:handle_sync_event,allows handling event regardless of current state. current state name is passed into handle_sync_event

{ok, Pid} = drop_sup:start_link().

1> c(drop_app).

{ok,drop_app}

2> code:add_path("ebin/").

true

3> application:load(drop).

ok

4> application:loaded_applications().

[{kernel,"ERTS  CXC 138 10","2.15.2"},

 {drop,"Dropping objects from towers","0.0.1"},

 {stdlib,"ERTS  CXC 138 10","1.18.2"}]

5> application:start(drop).

ok

6> gen_server:call(drop, 60).

{ok,34.292856398964496}


REBAR3 

Rebar3 is an Erlang tool that makes it easy to create, develop, and release Erlang libraries, applications, and systems in a repeatable manner. If you are from java programming, it is like maven. Hex is the repository to publish erlang library and searching, downloading library.

For installing rebar3 

https://github.com/erlang/rebar3

https://rebar3.readme.io/docs/getting-started

 

PATH=$PATH:$HOME/bin

export PATH=$PATH:~/.cache/rebar3/bin

 

Compile with rebar3: $rebar3 compile

Running with rebar3: $rebar3 shell

Publishing to hex: $ rebar3 hex publish -r test_repo


Erlang commands:

q()

Quits the shell and the Erlang runtime.

c(file)

Compiles the specified Erlang file.

b()

Displays all variable bindings.

f()

Clears all variable bindings.

f(X)

Clears specified variable binding.

h()

Prints the history list of commands.

e(N)

Repeats the command on line N.

v(N)

The return value of line N.

catch_exception(boolean)

Sets how strict the shell will be in passing errors.

rd(Name, Definition)

Defines a record type Name with contents specified by Definition.

rr(File)

Defines record types based on the contents of File.

rf()

Clears all record definitions. Can also clear specific definitions.

rl()

Lists all current record definitions.

pwd()

Gets the present working directory.

ls()

Lists files at the current location.


RESOURCES:

Dockerizing:

Git 2.0 installation:

Install java 11: yum -y install  java-11-openjdk java-11-openjdk-devel

Thursday, 16 December 2021

12 Factor App Principles

 

The Twelve-Factor App methodology is a methodology for building software-as-a-service applications. These best practices are designed to enable applications to be built with portability and resilience when deployed to the web.

1.      Code base

use version control, one repo per application, git submodule, maven submodule

2.      Dependencies:

don't check jar in git, use maven, artifactory, gcp artifact

3.      Config:

configuration should be strictly separated from code. As per "config", what varies for the environment to the environment must be moved to configurations and managed via environment variables.         

-        Database connections and credentials, system integration endpoints

-        Credentials to external services such as Amazon S3 or Twitter or any other external apps

-        Application-specific information like IP Addresses, ports, and hostnames, etc.

Principle: can you make your app opensource at anytime without compromising credentials

4.      Backing service:

Database, Message Brokers, any other external systems that the app communicates is treated as Backing service. Treat backing services as attached resources. like messaging service, postgre sql with signle url that can be replaced without making your code change

5.      Build, release, run:

Build stage: transform the code into an executable bundle/ build package.

Release stage: get the build package from the build stage and combines with the configurations of the deployment environment and make your application ready to run.

Run stage: It is like running your app in the execution environment.

Strictly separate the process with single command. You can use CI/CD tools to automate the builds and deployment process. Docker images make it easy to separate the build, release, and run stages more efficiently.

6.      Processes:

Execute the app as one or more stateless processes

As per 12-factor principles, the application should not store the data in in-memory and it must be saved to a store and use from there. As far as the state concern, your application should store the state in the database instead of in memory of the process.

Avoid using sticky sessions, using sticky sessions are a violation of 12-factor app principles. If you would store the session information, you can choose redis or memcached or any other cache provider based on your requirements.

7.      Port binding :

Export services via port binding. The web app exports HTTP as a service by binding to a port and listening to requests coming in on that port. Spring boot is one example of this one. Spring boot by default comes with embedded tomcat, jetty, or undertow.

8.      Concurrency:

By adopting the containerization, applications can be scaled horizontally as per the demands.

9.      Disposability

Maximize robustness with fast Startup and graceful shutdown. Docker containers can be started or stopped instantly. Storing request, state, or session data in queues or other backing services ensures that a request is handled seamlessly in the event of a container crash.

10.  Dev/prod parity

Keep development, staging, and production as similar as possible. This reduces the risks of showing up bugs in a specific environment.

11.  Logs

Treat logs as event streams

observability is the first-class citizen. Observability can be achieved through using APM tools (ELK, Newrelic, and other tools) or log aggregations tools like Splunk, logs, etc.

12.  Admin processes

Run admin/management tasks as one-off processes. Any needed admin tasks should be kept in source control and packaged with the application.

Twelve-factor principles advocates for keeping such administrative tasks as part of the application codebase in the repository. By doing so, one-off scripts follow the same process defined for your codebase.

Ensure one-off scripts are automated so that you don't need to worry about executing them manually before releasing the build. Twelve-factor principles also suggest using the built-in tool of the execution environment to run those scripts on production servers. 

Ref: https://12factor.net/

Friday, 18 June 2021

Continuous Integration Vs Continuous Delivery Vs Continuous Deployment



   Delivery of development and tested code is considered continuous integration