We distribute our application and code changes to multiple customers with various topologies via standard . NTF templates.
For scheduled agents in particular the behavior of Design Refresh creates a challenge since server names, enabled/disabled ,frequency and schedule properties vary per site. Current behavior of Design Refresh is an "All or Nothing" proposition. Under default settings each night, when designer runs, the agent is aligned completely with the Template definition which will reset schedules and other runtime settings (in addition to the code changes).
The other option is to set the Design Property "Prohibit design refresh or replace to modify". Since this option shuts off all updates, it become impossible to transmit code changes to a customer without manual intervention at each site.
While in practice, to minimize the impact of this situation, we attempt to keep the agent design as simple as possible , typically a single simple call into a script library ... it is inevitable a change will be needed at some point in time. Distribution of even a small code change to a schedule agent creates a lot of manual intervention at customer sites that should be unnecessary.
We either need designer task behavior to change when dealing with Agents or add a design property option to disable design refresh of Only the agent's runtime properties (server, schedule, enable/disabled). This would allow updates to the underlying program code as needed as part of the automated Designer task
An even simpler idea is to create an agent that has one (1) call, no arguments, into a script library. Then you can update thje code WITHOUT updating the agent. This separates the operational configuration of the agent from the implementation of its workings. Thus you can update the code without touching the agent. Works great for me. Whish they would do this more often in the product templates, which while largely great sometimes have abysmal design.
What you can do is to create one scheduled agent (which is disabled for design refresh) that only runs another agent which contains all your code.
Our standard practice is to put the bulk of the code in a script library. However as described above there are times, even the basic call in the top level agent needs to change.
Local security / signing is an issue. Many agents need specific rights to perform required tasks.
Some further thoughts. The items that control the server name and schedule are signed items. This means if design refresh fails to update them, the signature on the agent design note is invalid, and the agent will not run.
We could make them unsigned items, but in that case, I'm concerned about increased security exposure. Currently, it requires the access of a server administrator to enable an agent to run with full privileges on the server. With this change, anyone with Developer access to any application on the server, could do that. They would be limited in that they could only use agents which had been signed with an authorized ID, but they have their pick of ANY agent that is so signed, which they could copy from another application, and they could make that code run at a time, on a server, and in a context the developer didn't intend.
We're discussing whether this is acceptable. In the meantime, as an alternate workaround, you can set the agents to run "never", and set up their schedule using Program documents in the server address book:
Program name: nserver.exe
Command line: -c "Tell Amgr Run 'whatever.nsf' 'agentname"
This does sound like a good idea. Meanwhile, I suggest putting the bulk of your agent code into a script library so that your agent code can consist of one function call that you never need to change. Those can be protected from refresh, while still letting you update the library.
You could use the Notes API to do a scheduled design replace (rather than relying on the design task to refresh a design) without disturbing scheduled agent settings, viz:
Declare Function DesignReplace Lib "nnotes.dll" Alias "DesignReplace" ( ByVal ht As Long, ByVal hdb As Long, ByVal dw1 As Long, ByVal dw2 As Long, ByVal dw3 As Long, ByVal dw4 As Long ) As Integer