Giter Club home page Giter Club logo

ultraman's Introduction

Ultraman (Rust Foreman)

Release Periodic Regression License

Manage Procfile-based applications.

This is a foreman rust implementation made with ruby.
So the specifications are exactly the same as ruby ​​foreman.

πŸš‰ Platform

  • Linux
  • macOS
  • windows (Do not Support)

πŸ¦€ Installation

Download binary

Download from release page, and extract to the directory in PATH.

If you want to install the man,

Suppose you unzip the archive in the ./tmp directory

install -Dm644 ./tmp/ultraman.1 /usr/local/share/man/man1/ultraman.1

or

git clone [email protected]:yukihirop/ultraman.git && cd ultraman
make install_man

Homebrew

brew tap yukihirop/homebrew-tap
brew install ultraman

πŸ’» Command

$ ultraman --help
ultraman 0.3.0
Ultraman is a manager for Procfile-based applications. Its aim is to abstract away the details of the Procfile format,
and allow you to either run your application directly or export it to some other process management format.

USAGE:
    ultraman [SUBCOMMAND]

FLAGS:
    -h, --help       Prints help information
    -V, --version    Prints version information

SUBCOMMANDS:
    check     Validate your application's Procfile
    export    Export the application to another process management format
    help      Prints this message or the help of the given subcommand(s)
    run       Run a command using your application's environment
    start     Start the application

πŸš€ Tutorial

Create a Procfile like the one below

exit_0: sleep 5 && echo 'success' && exit 0;
exit_1: sleep 5 && echo 'failed' && exit 1;
loop: while :; do sleep 1 && echo 'Hello World'; done;

Then execute the following command

ultraman start

image

$ ultraman start
02:22:34 system    | exit_1.1  start at pid: 23374
02:22:34 system    | loop.1    start at pid: 23375
02:22:34 system    | exit_0.1  start at pid: 23376
02:22:35 loop.1    | Hello World
02:22:36 loop.1    | Hello World
02:22:37 loop.1    | Hello World
02:22:38 loop.1    | Hello World
02:22:39 exit_1.1  | failed
02:22:39 exit_0.1  | success
02:22:39 exit_0.1  | exited with code 0
02:22:39 system    | sending SIGTERM for exit_1.1  at pid 23374
02:22:39 system    | sending SIGTERM for loop.1    at pid 23375
02:22:39 exit_1.1  | exited with code 1
02:22:39 system    | sending SIGTERM for loop.1    at pid 23375
02:22:39 loop.1    | terminated by SIGTERM

If ctrl-c is detected within 5 seconds, SIGTERM will be sent to all child processes and the process will be killed.

image

$ ultraman start
02:23:58 system    | loop.1    start at pid: 23588
02:23:58 system    | exit_0.1  start at pid: 23589
02:23:58 system    | exit_1.1  start at pid: 23590
02:23:59 loop.1    | Hello World
02:24:00 loop.1    | Hello World
02:24:01 loop.1    | Hello World
^C02:24:01 system  | SIGINT received, starting shutdown
02:24:01 system    | sending SIGTERM to all processes
02:24:01 system    | sending SIGTERM for loop.1    at pid 23588
02:24:01 system    | sending SIGTERM for exit_0.1  at pid 23589
02:24:01 system    | sending SIGTERM for exit_1.1  at pid 23590
02:24:01 exit_1.1  | terminated by SIGTERM
02:24:01 exit_0.1  | terminated by SIGTERM
02:24:01 loop.1    | terminated by SIGTERM

🌎 Environment

  • rustc 1.74.0 (79e9716c9 2023-11-13) (Homebrew)
  • cargo 1.74.0

⚾️ Example

command link
ultraman start README.md
ultraman run README.md
ultraman export README.md
ultraman check README.md

πŸ’ͺ Development

cargo run start
cargo run run <app>
cargo run export <format> <location>

If you want to see help In that case, you can check with the following command

cargo run -- --help
cargo run start --help
cargo run run --help
cargo run export --help

✍️ Test

src/signal.rs usually ignores tests that need to send a SIGINT to kill the process as it can interrupt other tests

cargo test
cargo test -- --ignored # unit test about src/signal.rs
# or
cargo test -- --nocapture

πŸ‘½ Development in Docker

It is useful when a person developing on mac wants to check the operation on ubuntu.

{
    docker-compose build
    docker-compose up -d
    docker exec -it ultraman_test_ubuntu_1 /bin/bash
}

# in docker
root@65241fa12c67:/home/app# make test

πŸ§” Man

view man

make man

install man

make install_man

πŸ“š Reference

I really referred to the implementation of the following repository.

ultraman's People

Contributors

dan-da avatar yukihirop avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

ultraman's Issues

Fix rustman start

Summary

  • Refactor log for rustman start
  • Remove COLOR environment
  • Different from the options offered by foreman

root option is not supported as it is not about

$ bin/foreman help start
Usage:
  foreman start [PROCESS]

Options:
  -c, [--color], [--no-color]          # Force color to be enabled
  -e, [--env=ENV]                      # Specify an environment file to load, defaults to .env
  -m, [--formation="alpha=5,bar=3"]    # Specify what processes will run and how many. Default: "all=1"
  -p, [--port=N]
  -t, [--timeout=N]                    # Specify the amount of time (in seconds) processes have to shutdown gracefully before receiving a SIGKILL, defaults to 5.
      [--timestamp], [--no-timestamp]  # Include timestamp in output
                                       # Default: true
  -f, [--procfile=PROCFILE]            # Default: Procfile
  -d, [--root=ROOT]                    # Default: Procfile directory

Start the application (or a specific PROCESS)

Fix port option type

Even though the default value is 5000, it was handled as Optional for some reason

#[structopt(name = "PORT", short = "p", long = "port")]
    pub port: Option<String>,

↓

#[structopt(name = "PORT", short = "p", long = "port", default_value="5000")]
    pub port: String,

how to set the default formation?

Is there some equivalent to the .foreman file for setting default options? I tried both .foreman and .ultraman but it doesn't seem to read either.

from https://ddollar.github.io/foreman/

DEFAULT OPTIONS
If a .foreman file exists in the current directory, default options will be read from it. This file should be in YAML format with the long option name as keys. Example:

formation: alpha=0,bravo=1
port: 15000

Add ultraman example

Introduce detailed examples for the following commands

  • cargo start
  • cargo run
  • cargo export

It would be nice if there was an example using the full option

The base port value is incorrect

Summary

$ ultraman start
22:11:30 system | web.1  start at pid: 91352
22:11:32 web.1  | => Booting Puma
22:11:32 web.1  | => Rails 5.2.4.4 application starting in development
22:11:32 web.1  | => Run `rails server -h` for more startup options
22:11:32 web.1  | Puma starting in single mode...
22:11:32 web.1  | * Version 3.12.6 (ruby 2.5.3-p105), codename: Llamas in Pajamas
22:11:32 web.1  | * Min threads: 5, max threads: 5
22:11:32 web.1  | * Environment: development
22:11:32 web.1  | * Listening on tcp://localhost:4999
22:11:32 web.1  | Use Ctrl-C to stop
22:12:05 web.1  | Started GET "/" for ::1 at 2020-12-25 22:12:05 +0900

Expected

port is 5000

Version

$ ultraman --version
ultraman "0.1.2 ( rev: c5d1f03, rustc: 1.48.0, build at: 2020/12/25 12:29:56 )"

Implement rustman run

Summary

$ bin/foreman help run
Usage:
  foreman run COMMAND [ARGS...]

Options:
  -e, [--env=ENV]            # Specify an environment file to load, defaults to .env
  -f, [--procfile=PROCFILE]  # Default: Procfile
  -d, [--root=ROOT]          # Default: Procfile directory

Run a command using your application's environment

[Bug] Do not work: cargo run start -m "all=2"

Summary

all=2 formation is not supported...

$ cargo run start -m "all=2"
warning: unused import: `Path`
  --> src/cmd/export/upstart.rs:11:17
   |
11 | use std::path::{Path, PathBuf};
   |                 ^^^^
   |
   = note: `#[warn(unused_imports)]` on by default

warning: use of deprecated function `dotenv::from_path_iter`: please use `from_path` in conjunction with `var` instead
  --> src/env.rs:10:25
   |
10 |     if let Some(iter) = dotenv::from_path_iter(filepath.as_path()).ok() {
   |                         ^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: `#[warn(deprecated)]` on by default

warning: 2 warnings emitted

    Finished dev [unoptimized + debuginfo] target(s) in 0.24s
     Running `target/debug/rustman start -m all=2`
thread 'main' panicked at 'Do not support formation: all=2', src/procfile.rs:63:13
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

env vars are not consistent

Heya, thanks for making this project!

Steps to reproduce

The line from our procfile is web: bundle exec puma -p $PORT -C ./config/puma.rb, and a .env with PORT=3000, we see inconsistent results when running.

We're running via ultraman start.

Expected behavior

The server starts on port 3000

Actual behavior

The server starts on inconsistent ports, but always a multiple of 100, and always near the correct value of 3000. 3100 and 3200 are common values. Sometimes it is correct with 3000 as well.

e.g.

11:08:01 web.1              | 2023-12-11T19:08:01.393Z pid=103762 tid=2f5u INFO: Sidekiq 7.2.0 connecting to Redis with options {:size=>10, :pool_name=>"internal", :url=>nil}
11:08:01 web.1              | [103762] * Listening on http://0.0.0.0:3100 <-------------------- 
11:08:01 web.1              | [103762] Use Ctrl-C to stop
11:08:01 web.1              | [103762] - Worker 0 (PID: 104330) booted in 0.01s, phase: 0
11:08:01 web.1              | [103762] - Worker 1 (PID: 104334) booted in 0.01s, phase: 0
11:08:01 web.1              | [103762] - Worker 2 (PID: 104341) booted in 0.01s, phase: 0
11:08:01 web.1              | [103762] - Worker 3 (PID: 104354) booted in 0.0s, phase: 0

Stopping the server, waiting a minute or so, and re-running then puts it on a different port:

11:10:14 web.1 | [108858] * Listening on http://0.0.0.0:3200

Running the bundle exec line directly in a shell always starts the server on port 3000 as expected. Other foreman implementations also work as expected.

If -p $PORT is not specified in the procfile, the server consistently starts on port 9292, which is the expected default.

If we hardcode -p 3000 in the procfile, the server starts consistently on port 3000.

System configuration

ultraman version: 0.3.0

Rust version: 1.74.1

add profiler for develop

Summary

Allows you to profile in the development environment
If you are using macOS, run the following in a terminal in recovery mode to release SIP

csrutil enable --without dtrace

e.g)

cargo install flamegraph
sudo -E CARGO_PROFILE_RELEASE_DEBUG=true cargo flamegraph -o flamegraph-`date +%Y%m%d_%H%M%S`.svg --bin=ultraman -- start -f ./tmp/Procfile

image

Can not cargo package

Summary

$ cargo package
    Updating git repository `https://github.com/yukihirop/roff-rs`
error: failed to select a version for the requirement `roff = "^0.1.0"`
candidate versions found which didn't match: 0.2.0
location searched: Git repository https://github.com/yukihirop/roff-rs
required by package `ultraman v0.1.0 (/Users/yukihirop/RustProjects/ultraman)`

Cause

Versions not registered in creates-io cannot be referenced. I can't get a crate from github

roff = { version = "0.2.0", git = "https://github.com/yukihirop/roff-rs", tag = "v0.2.0" }

There is a method other than crates-io to create a repository and take it from there.

Memo

update deps version

I haven't maintained it for a while, so I will upgrade the version of the old deps.

Add badges

Summary

Add badges

  • crates.io
  • github ci
  • man??

ultraman panics if a process is exiting early while processing the stdio of that process

Steps to reproduce

Simple reproduce (my env is a bit different, and reproduce the panic 100%)

Profile:

early_out: seq 100
sleep: sleep 20

Expected behavior

full 100 lines are displayed to the terminal

Actual behavior

only few lines are displayed.
sometimes, a panic happens:

thread '' panicked at 'called Result::unwrap() on an Err value: "SendError(..)"', #44 $HOME/.cargo/registry/src/index.crates.io-6f17d22bba15001f/ultraman-0.3.1/src/stream_read.rs:44:38

It looks like there is a race-condition between catch of the SIGCHILD, and completion of the stdout/err processing.

System configuration

ultraman version:
0.3.1
Rust version:

Fail test in ubuntu

Summary

image

Todo

Prepare an environment that can be tested with docker (ubuntu) or vagrant and check it

ultraman pegs CPU usage.

I like how easy ultraman is to setup and use, but...

ultraman is using 100% of one cpu core. I made a test case that simply execs a bash script that calls sleep 5000.

$ cat sleep.sh
sleep 5000

$ cat Procfile 
sleep1: ./sleep.sh
sleep2: ./sleep.sh
sleep3: ./sleep.sh

$ ultraman start
17:40:53 system    | sleep3.1  start at pid: 3208
17:40:53 system    | sleep2.1  start at pid: 3210
17:40:53 system    | sleep1.1  start at pid: 3209

top, in other shell:

  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                            
 3204 user      20   0  759540   4204   3848 S 100.0  0.0   0:55.90 ultraman
$ which ultraman
/home/user/.cargo/bin/ultraman
$ ultraman --version
ultraman 0.1.2

I built ultraman at commit c5d1f03

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.