I'm using IBM Integration Bus Version 10.0.0.15 and I'm looking for an option to intialize shared variables during the startup of a message flow, for example uing the command mqsistartmsgflow. Is there a special procedure or function one can implement with ESQL which is guranteed to be excuted during start up?
In the ESQL documentation it is stated that shared variables are intialized when the first message is routed through the flow which means you have to wait for the first message.
Actually you need to initialise them this typically looks something like.
-- Shared row variable for caching config data. Declared at Global scope.
DECLARE S_ConfigSharedRow SHARED ROW;
CREATE COMPUTE MODULE TheFirstComputeNode
CREATE FUNCTION Main() RETURNS BOOLEAN
BEGIN
CFGDATA_CACHE_LOCK: BEGIN ATOMIC
-- If the configuration data is not available in the cache then load it from the CONFIG table
DECLARE CfgDataRef REFERENCE TO S_ConfigSharedRow.CfgDataCache;
IF NOT LASTMOVE(CfgDataRef) THEN
-- Select all the relevant content from the actual database in one go.
DECLARE DBResults ROW;
DECLARE RetryCount INTEGER 5;
SET DBResults.Row[] = PASSTHRU('SELECT * FROM CONFIG');
-- Typically you would post process the content from the DB into a more amenable
-- structure but the following will get the data into the shared variable
CREATE LASTCHILD OF S_ConfigSharedRow.CfgDataCache FROM DBResults;
END IF;
END CFGDATA_CACHE_LOCK;
-- Config data is now available for use
RETURN TRUE;
END;
END MODULE;
I think the best way is to have a dedicated flow for initializing shared variables.
That flow should have an input queue separate from the normal input queue, just for sending in messages to trigger the initialization.
Then you should make a startup script, which sends a message to this init flow after starting up the main processing flow.
And use only that script for startup.
If you want another option, you could include a JavaCompute node and add some once-only initialisation into its class using a static initialization block. You would only be able to initialize Java data structures this way, though.
Related
I created an Oracle PL/SQL package which I want to prevent being executed in a production environment, or on a specific database, which could be dangerous. Indeed, it turns out I have admin rights and could inadvertently compile the Developement package in a production environment.
I tried checking the context in my package's body with something similar to this:
create or replace package body my_test_package is
context varchar2(64);
function get_context return varchar2 is
begin
-- return context: DEV or PROD
...
end;
-- list of other functions & procedures ....
begin
if context = 'PROD' then
dbms_standard.raise_application_error(-20001, 'production context, prevent execution of this package');
end if;
end;
However, I know it is bad solution because the initialization time takes place only once, as stated by Oracle documentation:
The initialization part of a package plays a minor role because, unlike subprograms, a package cannot be called or passed parameters. As a result, the initialization part of a package is run only once, the first time you reference the package.
So, that means all subsequent procedure calls following the first one will be executed, even in a production environment. E.g:
-- production environment
begin
my_test_package.dangerous_procedure();
exception when others then
dbms_output.put_line('bypass context exception');
end;
my_test_package.dangerous_procedure(); ---> EXECUTED IN PROD :(
Is there a common idiom or a known approach to prevent a package from being executed in a particular environment? (e.g. without having to copy the same piece of code in each procedure/function of the package, to check it has the right to execute).
Thanks
It is common to have this requirement in the opposite direction: i.e., you have processes that run in PROD that you do not want to run (or not run the same way) in DEV. For example, you might have a program that generates a file and FTPs it to a trading partner. You wouldn't want that to run in DEV by accident after a clone from PROD.
We build the implementation for requirements into our code, rather than relying on database-level things like dropping objects in certain environments (or constantly re-installing things in DEV instances after a clone) and/or revoking security. By building things into our code, we have the flexibility not just to prevent something from running in one instance or another, but to let it run but run differently (e.g., generate the FTP file, but send it to a test server instead of the trading partner).
To do this, we have a piece of data that has the name of the production database (we use an application feature called "profile values" for this, but you can just put it in a custom table).
Then, in any environment-sensitive process:
BEGIN
l_db_name := xxcust_common_utils_pkg.get_production_dbname; -- you write this function based on where you put the production database name...
IF sys_context('USERENV','DB_NAME') = l_db_name THEN
... act like you want to in production
ELSE
... act like you want to in non-production
END IF;
END;
It's very simple, but unfortunately does require coding.
I am using a collector node on IIB to collect a set of messages. Can someone help with sample ESQL after collector node to process a message collection? Since I am new to ESQL I am struggling to figure it out. The IBM info center is not very helpful on ESQL message collection.
The code would depend on what you want to do with the collection. If you want to loop through the collected messages, you could do something like this:
--reference the first message, the CollectionName is the first element in the array
DECLARE ref REFERENCE TO InputRoot.Collection.[2];
WHILE LASTMOVE(ref) DO
--reference the data like normal, domain is a header, parsers, etc.
SET Environment.Variables.data = ref.domain.data;
--example ref.XMLNSC.HTML.Body.h1
--do any other work on the message here
MOVE ref NEXTSIBLING;
END WHILE;
This loop will run until it reaches the end of the collection. Then the MOVE command will return null and the LASTMOVE will return false.
Use a Trace node before the ESQL with the pattern ${Root} to see what the message structure looks like. This is the best place to start to develop the ESQL you need to process the data.
Let's say I have some data :: Vector{Float64} and a function f!(data::Vector{Float64}, i::Int) that calculates some value from it, modifying it in the process.
answers = pmap([1,2,3,4]) do i
f!(data, i)
end
Is this safe to do? Does each worker have its own copy of data, or should I explicitly copy(data) on all workers?
That is safe to do and will create a closure that puts the data in the function and sends the function with the data to each process. If you use a CachingPool it will make sure that data is only sent to each worker once (in Julia v0.7 and 1.0 this will be done by default).
I have one messagehandler in the form like this:
procedure TMain_Form.form_message_handler(var MSG: TMessage);
begin
case MSG.WParam of
0: global_variable:=10;
1: global_variable:=global_variable+100;
end;
end;
Several threads will send to it asynchronous messages - PostMessage. Is manipulation of global variables (within such a handler) safe - I mean that access to these variables is safe? I will plan to manipulate this global variables only inside this handler. I assume it is safe because the messages handled by the handler waiting for execution in the queue. Is my assumption is correct?
Not really, no. If you are going to send asynchronous messages via. PostMessage, (not that it's a bad idea - hugely better than the apalling TThread.Synchronize), try very hard to post ALL of the data required by the message-handler, ie. do not use globals. If you have to communicate a lot of stuff, post a struct or object pointer in wParam/lParam.
Do not use globals unless... nothing really.
Oh, and another thing - do not use globals.
VCL is not thread safe. Therefore I guess it is not a good idea to write information to the gui in the INDY 10 TCP server.execute(...) function .
How to send information from the server execute to the VCL ?
I need to modify a TBitmap inside a tcpserver.execute function. How to make that thread safe ?
Write stuff to the VCL thread from Indy the same way to write stuff to the VCL thread from anywhere else. Common options include TThread.Synchronize and TThread.Queue.
Modifying a standalone TBitmap should not require synchronization with the main thread. You can modify it from any thread you want, as long as you do it from only one thread at a time. You can use the standard synchronization objects like critical sections and events to make sure only one thread uses it at a time.
the best way to synch is by creating and using a TidNotify descendant.
define a tidnotify descendant and vcl proc like this with the appropriate private fields.
TVclProc= procedure(aBMP: TBitmap) of object;
TBmpNotify = class(TIdNotify)
protected
FBMP: TBitmap;
FProc: TVclProc;
procedure DoNotify; override;
public
constructor Create(aBMP: TBitmap; aProc: TVclProc); reintroduce;
class procedure NewBMP(aBMP: TBitmap; aProc: TVclProc);
end;
then implement it like this
{ TBmpNotify }
constructor TBmpNotify.Create(aBMP: TBitmap; aProc: TVclProc);
begin
inherited Create;
FBMP:= aBMP;
FProc:= aProc;
end;
procedure TBmpNotify.DoNotify;
begin
inherited;
FProc(FBMP);
end;
class procedure TBmpNotify.NewBMP(aBMP: TBitmap; aProc: TVclProc);
begin
with Create(aBMP, aProc) do
begin
Notify;
end;
end;
then from the
server.execute(...)
call it like this
procedure TTCPServer.DoExecute(aContext: TIdContext);
var
NewBMP: TBitmap;
begin
TBmpNotify.NewBMP(NewBMP, FVclBmpProc);
end;
Where the FVclBmpProcis a private field pointing to a procedure on the form that matches the parameter signature of TVclProc. This field should be set via a property on the server object just after creation and before starting the server.
the method on the form will be free to use the bitmap it receives without fear of thread contention, deadlock and other nasties created by accessing the VCL controls without synchronisation.
One simple PostMessage (inside the thread) and handling message (outside the thread) was necessary to make UI updates...