• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

supabase / edge-runtime / 23229475223

18 Mar 2026 04:43AM UTC coverage: 53.308% (-0.03%) from 53.338%
23229475223

Pull #674

github

web-flow
Merge 9a4f0c174 into 564363c3e
Pull Request #674: feat: add independent OTLP span instrumentation for V8 event loop

55 of 97 new or added lines in 3 files covered. (56.7%)

25 existing lines in 7 files now uncovered.

19529 of 36634 relevant lines covered (53.31%)

7368.37 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/cli/src/main.rs
1
use std::fs::File;
2
use std::io::Write;
3
use std::net::IpAddr;
4
use std::net::SocketAddr;
5
use std::path::PathBuf;
6
use std::process::ExitCode;
7
use std::str::FromStr;
8
use std::sync::Arc;
9
use std::time::Duration;
10

11
use anyhow::bail;
12
use anyhow::Context;
13
use anyhow::Error;
14
use base::server;
15
use base::server::Builder;
16
use base::server::RequestIdleTimeout;
17
use base::server::ServerFlags;
18
use base::server::Tls;
19
use base::utils::units::percentage_value;
20
use base::worker::pool::SupervisorPolicy;
21
use base::worker::pool::WorkerPoolPolicy;
22
use base::CacheSetting;
23
use base::InspectorOption;
24
use base::WorkerKind;
25
use deno::deno_telemetry;
26
use deno::deno_telemetry::OtelConfig;
27
use deno::ConfigMode;
28
use deno::DenoOptionsBuilder;
29
use deno_facade::extract_from_file;
30
use deno_facade::generate_binary_eszip;
31
use deno_facade::EmitterFactory;
32
use deno_facade::Metadata;
33
use env::resolve_deno_runtime_env;
34
use flags::get_cli;
35
use flags::EszipV2ChecksumKind;
36
use flags::OtelConsoleConfig;
37
use flags::OtelKind;
38
use log::warn;
39
use tokio::time::timeout;
40

41
mod env;
42
mod flags;
43

44
#[cfg(not(feature = "tracing"))]
45
mod logger;
46

47
fn main() -> Result<ExitCode, anyhow::Error> {
×
48
  resolve_deno_runtime_env();
×
49

×
50
  let runtime = tokio::runtime::Builder::new_current_thread()
×
51
    .enable_all()
×
52
    .thread_name("sb-main")
×
53
    .build()
×
54
    .unwrap();
×
55

×
56
  // TODO: Tokio runtime shouldn't be needed here (Address later)
×
57
  let local = tokio::task::LocalSet::new();
×
58
  let res: Result<ExitCode, Error> = local.block_on(&runtime, async {
×
59
    let matches = get_cli().get_matches();
×
60
    let verbose = matches.get_flag("verbose");
×
61

×
62
    if !matches.get_flag("quiet") {
×
63
      #[cfg(feature = "tracing")]
64
      {
65
        use tracing_subscriber::fmt::format::FmtSpan;
66
        use tracing_subscriber::EnvFilter;
67

68
        tracing_subscriber::fmt()
69
          .with_env_filter(EnvFilter::from_default_env())
70
          .with_thread_names(true)
71
          .with_span_events(if verbose {
72
            FmtSpan::FULL
73
          } else {
74
            FmtSpan::NONE
75
          })
76
          .init()
77
      }
78

79
      #[cfg(not(feature = "tracing"))]
80
      {
×
81
        let include_source = matches.get_flag("log-source");
×
82
        logger::init(verbose, include_source);
×
83
      }
×
84
    }
×
85

86
    #[allow(clippy::single_match)]
87
    #[allow(clippy::arc_with_non_send_sync)]
88
    let exit_code = match matches.subcommand() {
×
89
      Some(("start", sub_matches)) => {
×
90
        deno_telemetry::init(
×
91
          deno::versions::otel_runtime_config(),
×
92
          OtelConfig::default(),
×
93
        )?;
×
NEW
94
        base::runtime::otel::init_if_needed();
×
95

×
96
        let ip = sub_matches.get_one::<String>("ip").cloned().unwrap();
×
97
        let ip = IpAddr::from_str(&ip)
×
98
          .context("failed to parse the IP address to bind the server")?;
×
99

100
        let port = sub_matches.get_one::<u16>("port").copied().unwrap();
×
101

×
102
        let addr = SocketAddr::new(ip, port);
×
103

104
        let maybe_tls =
×
105
          if let Some(port) = sub_matches.get_one::<u16>("tls").copied() {
×
106
            let Some((key_slice, cert_slice)) = sub_matches
×
107
              .get_one::<PathBuf>("key")
×
108
              .and_then(|it| std::fs::read(it).ok())
×
109
              .zip(
×
110
                sub_matches
×
111
                  .get_one::<PathBuf>("cert")
×
112
                  .and_then(|it| std::fs::read(it).ok()),
×
113
              )
×
114
            else {
115
              bail!("unable to load the key file or cert file");
×
116
            };
117

118
            Some(Tls::new(port, &key_slice, &cert_slice)?)
×
119
          } else {
120
            None
×
121
          };
122

123
        let main_service_path = sub_matches
×
124
          .get_one::<String>("main-service")
×
125
          .cloned()
×
126
          .unwrap();
×
127

×
128
        let no_module_cache = sub_matches
×
129
          .get_one::<bool>("disable-module-cache")
×
130
          .cloned()
×
131
          .unwrap();
×
132

×
133
        let allow_main_inspector = sub_matches
×
134
          .get_one::<bool>("inspect-main")
×
135
          .cloned()
×
136
          .unwrap();
×
137

×
138
        let enable_otel = sub_matches
×
139
          .get_many::<OtelKind>("enable-otel")
×
140
          .unwrap_or_default()
×
141
          .cloned()
×
142
          .collect::<Vec<_>>();
×
143

×
144
        let otel_console = sub_matches
×
145
          .get_one::<OtelConsoleConfig>("otel-console")
×
146
          .cloned()
×
147
          .map(Into::into);
×
148

×
149
        let event_service_manager_path =
×
150
          sub_matches.get_one::<String>("event-worker").cloned();
×
151
        let maybe_main_entrypoint =
×
152
          sub_matches.get_one::<String>("main-entrypoint").cloned();
×
153
        let maybe_events_entrypoint =
×
154
          sub_matches.get_one::<String>("events-entrypoint").cloned();
×
155

×
156
        let maybe_supervisor_policy = sub_matches
×
157
          .get_one::<String>("policy")
×
158
          .map(|it| it.parse::<SupervisorPolicy>().unwrap());
×
159

×
160
        let graceful_exit_deadline_sec = sub_matches
×
161
          .get_one::<u64>("graceful-exit-timeout")
×
162
          .cloned()
×
163
          .unwrap_or(0);
×
164

×
165
        let graceful_exit_keepalive_deadline_ms = sub_matches
×
166
          .get_one::<u64>("experimental-graceful-exit-keepalive-deadline-ratio")
×
167
          .cloned()
×
168
          .and_then(|it| {
×
169
            if it == 0 {
×
170
              return None;
×
171
            }
×
172

×
173
            percentage_value(graceful_exit_deadline_sec * 1000, it)
×
174
          });
×
175

×
176
        let event_worker_exit_deadline_sec = sub_matches
×
177
          .get_one::<u64>("event-worker-exit-timeout")
×
178
          .cloned()
×
179
          .unwrap_or(0);
×
180

×
181
        let maybe_max_parallelism =
×
182
          sub_matches.get_one::<usize>("max-parallelism").cloned();
×
183
        let maybe_request_wait_timeout =
×
184
          sub_matches.get_one::<u64>("request-wait-timeout").cloned();
×
185
        let maybe_main_worker_request_idle_timeout = sub_matches
×
186
          .get_one::<u64>("main-worker-request-idle-timeout")
×
187
          .cloned();
×
188
        let maybe_user_worker_request_idle_timeout = sub_matches
×
189
          .get_one::<u64>("user-worker-request-idle-timeout")
×
190
          .cloned();
×
191
        let maybe_request_read_timeout =
×
192
          sub_matches.get_one::<u64>("request-read-timeout").cloned();
×
193

×
194
        let maybe_beforeunload_wall_clock_pct = sub_matches
×
195
          .get_one::<u8>("dispatch-beforeunload-wall-clock-ratio")
×
196
          .cloned();
×
197
        let maybe_beforeunload_cpu_pct = sub_matches
×
198
          .get_one::<u8>("dispatch-beforeunload-cpu-ratio")
×
199
          .cloned();
×
200
        let maybe_beforeunload_memory_pct = sub_matches
×
201
          .get_one::<u8>("dispatch-beforeunload-memory-ratio")
×
202
          .cloned();
×
203

204
        let static_patterns =
×
205
          if let Some(val_ref) = sub_matches.get_many::<String>("static") {
×
206
            val_ref.map(|s| s.as_str()).collect::<Vec<&str>>()
×
207
          } else {
208
            vec![]
×
209
          };
210

211
        let static_patterns: Vec<String> =
×
212
          static_patterns.into_iter().map(|s| s.to_string()).collect();
×
213

×
214
        let inspector = sub_matches.get_one::<clap::Id>("inspector").zip(
×
215
          sub_matches
×
216
            .get_one("inspect")
×
217
            .or(sub_matches.get_one("inspect-brk"))
×
218
            .or(sub_matches.get_one::<SocketAddr>("inspect-wait")),
×
219
        );
×
220

221
        let maybe_inspector_option = if let Some((key, addr)) = inspector {
×
222
          Some(get_inspector_option(key.as_str(), addr).unwrap())
×
223
        } else {
224
          None
×
225
        };
226

227
        let tcp_nodelay =
×
228
          sub_matches.get_one::<bool>("tcp-nodelay").copied().unwrap();
×
229
        let request_buffer_size = sub_matches
×
230
          .get_one::<u64>("request-buffer-size")
×
231
          .copied()
×
232
          .unwrap();
×
233
        let rate_limit_cleanup_interval_sec = sub_matches
×
234
          .get_one::<u64>("rate-limit-table-cleanup-interval")
×
235
          .copied()
×
236
          .unwrap_or(60);
×
237
        if rate_limit_cleanup_interval_sec == 0 {
×
238
          bail!("--rate-limit-table-cleanup-interval must be >= 1 second");
×
239
        }
×
240
        let flags = ServerFlags {
×
241
          otel: if !enable_otel.is_empty() {
×
242
            if enable_otel.len() > 1 {
×
243
              Some(server::OtelKind::Both)
×
244
            } else {
245
              match enable_otel.first() {
×
246
                Some(OtelKind::Main) => Some(server::OtelKind::Main),
×
247
                Some(OtelKind::Event) => Some(server::OtelKind::Event),
×
248
                None => None,
×
249
              }
250
            }
251
          } else {
252
            None
×
253
          },
254
          otel_console,
×
255

×
256
          no_module_cache,
×
257
          allow_main_inspector,
×
258
          tcp_nodelay,
×
259

×
260
          graceful_exit_deadline_sec,
×
261
          graceful_exit_keepalive_deadline_ms,
×
262
          event_worker_exit_deadline_sec,
×
263
          request_wait_timeout_ms: maybe_request_wait_timeout,
×
264
          request_idle_timeout: RequestIdleTimeout::from_millis(
×
265
            maybe_main_worker_request_idle_timeout,
×
266
            maybe_user_worker_request_idle_timeout,
×
267
          ),
×
268
          request_read_timeout_ms: maybe_request_read_timeout,
×
269
          request_buffer_size: Some(request_buffer_size),
×
270

×
271
          beforeunload_wall_clock_pct: maybe_beforeunload_wall_clock_pct,
×
272
          beforeunload_cpu_pct: maybe_beforeunload_cpu_pct,
×
273
          beforeunload_memory_pct: maybe_beforeunload_memory_pct,
×
274

×
275
          rate_limit_cleanup_interval_sec,
×
276
        };
×
277

×
278
        let mut builder = Builder::new(addr, &main_service_path);
×
279

×
280
        builder.user_worker_policy(WorkerPoolPolicy::new(
×
281
          maybe_supervisor_policy,
×
282
          if let Some(true) = maybe_supervisor_policy
×
283
            .as_ref()
×
284
            .map(SupervisorPolicy::is_oneshot)
×
285
          {
286
            if let Some(parallelism) = maybe_max_parallelism {
×
287
              if parallelism == 0 || parallelism > 1 {
×
288
                warn!(
×
289
                  "{}",
×
290
                  concat!(
291
                    "if `oneshot` policy is enabled, the maximum ",
292
                    "parallelism is fixed to `1` as forcibly ^^"
293
                  )
294
                );
295
              }
×
296
            }
×
297

298
            Some(1)
×
299
          } else {
300
            maybe_max_parallelism
×
301
          },
302
          flags,
×
303
        ));
304

305
        if let Some(tls) = maybe_tls {
×
306
          builder.tls(tls);
×
307
        }
×
308
        if let Some(worker_path) = event_service_manager_path {
×
309
          builder.event_worker_path(&worker_path);
×
310
        }
×
311
        if let Some(inspector_option) = maybe_inspector_option {
×
312
          builder.inspector(inspector_option);
×
313
        }
×
314

315
        builder.extend_static_patterns(static_patterns);
×
316
        builder.entrypoints_mut().main = maybe_main_entrypoint;
×
317
        builder.entrypoints_mut().events = maybe_events_entrypoint;
×
318

×
319
        *builder.flags_mut() = flags;
×
320

321
        let maybe_received_signum_or_exit_code =
×
322
          builder.build().await?.listen().await?;
×
323

324
        maybe_received_signum_or_exit_code
×
325
          .map(|it| it.map_left(|it| ExitCode::from(it as u8)).into_inner())
×
326
          .unwrap_or_default()
×
327
      }
328

329
      Some(("bundle", sub_matches)) => {
×
330
        let output_path =
×
331
          sub_matches.get_one::<String>("output").cloned().unwrap();
×
332
        let import_map_path =
×
333
          sub_matches.get_one::<String>("import-map").cloned();
×
334
        let decorator = sub_matches.get_one::<String>("decorator").cloned();
×
335
        let static_patterns =
×
336
          if let Some(val_ref) = sub_matches.get_many::<String>("static") {
×
337
            val_ref.map(|s| s.as_str()).collect::<Vec<&str>>()
×
338
          } else {
339
            vec![]
×
340
          };
341
        let timeout_dur = sub_matches
×
342
          .get_one::<u64>("timeout")
×
343
          .cloned()
×
344
          .map(Duration::from_secs);
×
345

×
346
        if import_map_path.is_some() {
×
347
          warn!(concat!(
×
348
            "Specifying import_map through flags is no longer supported. ",
×
349
            "Please use deno.json instead."
×
350
          ))
×
351
        }
×
352
        if decorator.is_some() {
×
353
          warn!(concat!(
×
354
            "Specifying decorator through flags is no longer supported. ",
×
355
            "Please use deno.json instead."
×
356
          ))
×
357
        }
×
358

359
        let entrypoint_script_path = sub_matches
×
360
          .get_one::<String>("entrypoint")
×
361
          .cloned()
×
362
          .unwrap();
×
363

×
364
        let entrypoint_script_path =
×
365
          PathBuf::from(entrypoint_script_path.as_str());
×
366
        if !entrypoint_script_path.is_file() {
×
367
          bail!(
×
368
            "entrypoint path does not exist ({})",
×
369
            entrypoint_script_path.display()
×
370
          );
×
371
        }
×
372

×
373
        let entrypoint_script_path =
×
374
          entrypoint_script_path.canonicalize().unwrap();
×
375

×
376
        let mut emitter_factory = EmitterFactory::new();
×
377

×
378
        if sub_matches
×
379
          .get_one::<bool>("disable-module-cache")
×
380
          .cloned()
×
381
          .unwrap()
×
382
        {
×
383
          emitter_factory.set_cache_strategy(Some(CacheSetting::ReloadAll));
×
384
        }
×
385

386
        let maybe_checksum_kind = sub_matches
×
387
          .get_one::<EszipV2ChecksumKind>("checksum")
×
388
          .copied()
×
389
          .and_then(EszipV2ChecksumKind::into);
×
390

×
391
        emitter_factory.set_permissions_options(Some(
×
392
          base::get_default_permissions(WorkerKind::MainWorker),
×
393
        ));
×
394

×
395
        let mut builder =
×
396
          DenoOptionsBuilder::new().entrypoint(entrypoint_script_path.clone());
×
397

398
        if let Some(path) = import_map_path {
×
399
          let path = PathBuf::from(path);
×
400
          if !path.exists() || !path.is_file() {
×
401
            bail!("import map path is incorrect");
×
402
          }
×
403
          builder.set_config(Some(ConfigMode::Path(path)));
×
404
        }
×
405
        emitter_factory.set_deno_options(builder.build()?);
×
406

407
        let mut metadata = Metadata::default();
×
408
        let eszip_fut = generate_binary_eszip(
×
409
          &mut metadata,
×
410
          Arc::new(emitter_factory),
×
411
          None,
×
412
          maybe_checksum_kind,
×
413
          Some(static_patterns),
×
414
        );
×
415

416
        let eszip = if let Some(dur) = timeout_dur {
×
417
          match timeout(dur, eszip_fut).await {
×
418
            Ok(eszip) => eszip,
×
419
            Err(_) => {
420
              bail!("Failed to complete the bundle within the given time.")
×
421
            }
422
          }
423
        } else {
424
          eszip_fut.await
×
425
        }?;
×
426

427
        let bin = eszip.into_bytes();
×
428

×
429
        if output_path == "-" {
×
430
          let stdout = std::io::stdout();
×
431
          let mut handle = stdout.lock();
×
432

×
433
          handle.write_all(&bin)?
×
434
        } else {
435
          let mut file = File::create(output_path.as_str())?;
×
436
          file.write_all(&bin)?
×
437
        }
438

439
        ExitCode::SUCCESS
×
440
      }
441

442
      Some(("unbundle", sub_matches)) => {
×
443
        let output_path =
×
444
          sub_matches.get_one::<String>("output").cloned().unwrap();
×
445
        let eszip_path =
×
446
          sub_matches.get_one::<String>("eszip").cloned().unwrap();
×
447

×
448
        let output_path = PathBuf::from(output_path.as_str());
×
449
        let eszip_path = PathBuf::from(eszip_path.as_str());
×
450

×
451
        if extract_from_file(eszip_path, output_path.clone()).await {
×
452
          println!(
×
453
            "Eszip extracted successfully inside path {}",
×
454
            output_path.to_str().unwrap()
×
455
          );
×
456
          ExitCode::SUCCESS
×
457
        } else {
458
          ExitCode::FAILURE
×
459
        }
460
      }
461

462
      _ => {
463
        // unrecognized command
464
        ExitCode::FAILURE
×
465
      }
466
    };
467

468
    Ok(exit_code)
×
469
  });
×
470

×
471
  res
×
472
}
×
473

474
fn get_inspector_option(
×
475
  key: &str,
×
476
  addr: &SocketAddr,
×
477
) -> Result<InspectorOption, anyhow::Error> {
×
478
  match key {
×
479
    "inspect" => Ok(InspectorOption::Inspect(*addr)),
×
480
    "inspect-brk" => Ok(InspectorOption::WithBreak(*addr)),
×
481
    "inspect-wait" => Ok(InspectorOption::WithWait(*addr)),
×
482
    key => bail!("invalid inspector key: {}", key),
×
483
  }
484
}
×
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc