вторник, 10 ноября 2009 г.

ADP shell wrapper

Для некоторых пакетных операций, например, построения и рассылки отчетов по расписанию, удобно иметь возможность запуска adp-скриптов напрямую из консоли. Задача, таким образом, состоит в том, чтобы обеспечить среду исполнения наподобии предоставляемой AOL Server. Воспользуемся интерпретатором nstclsh для доступа к функциям, предоставляемым AOL Server, а функции обращения к конфигурации и подобные подменим своими.

adp-wrapper.tcl

#!/usr/bin/nstclsh
# ./adp-wrapper.tcl .../report_ext_01/report_html_all.adp date 2009-10-01 user_id 265

set aol_root [string range [lindex $argv 0] 0 [string last www [lindex $argv 0]]-2]
array set args [lrange $argv 1 end]

rename puts _puts
proc puts {message} {}
proc ns_log {args} {}
proc ns_config {unit key} {
global aol_root
# puts "$unit => $key"
if {$key eq "timeout"} {return 10000}
if {$key eq "location"} {return [file join $aol_root res dataset]}
return
}
proc ns_register_proc {args} {}
proc ns_register_filter {args} {}
proc <% {} {}
proc %> {} {}
proc ns_adp_puts {val} {puts $val}
proc ns_adp_append {args} {foreach arg $args {puts -nonewline $arg}}
# значения переменных GET берутся из аргументов командной строки
proc ns_queryget {name} {
global args
if {[info exists args($name)] == 1} {
return $args($name)
}
return
}
proc ns_backup_cache_sheduler {args} {}
proc ns_backup_nsv_array_sheduler {args} {}
# загрузить необходимые функции
foreach unit {tcl_module ns_dataset ns_keys ns_menu ns_html populate billing telephony internet} {
foreach fname [glob [file join $aol_root tcl $unit *.tcl]] {
source $fname
}
}
rename puts {}
rename _puts puts
rename ns_adp_include orig_ns_adp_include
proc ns_adp_include {src} {
global argv
source [file join [file dirname [lindex $argv 0]] $src]
}

# выполнить adp-скрипт в подготовленном окружении
ns_adp_include [file tail [lindex $argv 0]]


Здесь функции ns_backup_cache_sheduler и ns_backup_nsv_array_sheduler обеспечивают восстановление состояние AOL Server после перезапуска, что нам, естественно, не требуется для эмуляции. Кроме того, структура директорий в корне веб-сервера жестко фиксирована, что позволяет по пути к adp-скрипту определить местонахождение баз данных и тиклевских скриптов, загружаемых при инициализации.

Использование "обертки" довольно тривиально:

#!/usr/bin/tclsh8.5
# start as
# AOLROOT=... ./telephony_report.tcl
package require sqlite3

if {[info exists env(AOLROOT)] == 0} {
puts stderr {Not defined environment variable AOLROOT}
exit
}

sqlite3 db :memory:
db restore [file join $env(AOLROOT) res dataset work].db
db timeout 2000
db cache size 100

set date [db onecolumn {select date('now','start of month','-1 month')}]
set user_id 229

db eval {SELECT id, login FROM view_user WHERE type != 'system' AND is_provider = 0
AND delete_date IS NULL ORDER BY name ASC} {
exec ./adp-wrapper.tcl $env(AOLROOT)/www/ext/report_ext_01/report_html_all.adp date $date user_id $id > \
$env(AOLROOT)/www/share/${login}_all.html 2>/dev/null
exec ./adp-wrapper.tcl $env(AOLROOT)/www/ext/report_ext_01/report_html_c.adp date $date user_id $id > \
$env(AOLROOT)/www/share/${login}_c.html 2>/dev/null
exec ./adp-wrapper.tcl $env(AOLROOT)/www/ext/report_ext_01/report_html_cd.adp date $date user_id $id > \
$env(AOLROOT)/www/share/${login}_cd.html 2>/dev/null
}
db close


Многоточием я заменил реальные пути на своем сервере.

Следует отметить, что для каждого запускаемого скрипта выполняется полная инициализация окружения, что неэффективно с вычислительной точки зрения. В случае, когда требуется высокое быстродействие, можно сделать аналогично применяемой в AOL Server технике - выполнять каждый скрипт в клоне проинициализированного интерпретатора. На мой взгляд, это несложно, но лишено смысла - удобнее будет обращаться по HTTP с соответствующими запросами (правда, придется или отключить авторизацию для таких запросов или реализовать ее в виде некоторой обертки, наподобии вышеописанной).

Комментариев нет:


(C) Alexey Pechnikov aka MBG, mobigroup.ru